Работа с "временной панелью" в своем плагине

Иван Синтюрин [spinoza@mail.ru]spinoza@mail.ru
http://www.moris.ru/~spinoza

Причиной написания данной статьи послужил, как мне кажется, наиболее эффективный на текущий день способ решения проблемы добавления собственным плагином "Поиск и Замена (S&R)" файлов на стандартную "временную панель" FAR, которым я и хочу поделиться с вами.

Немного истории Немного истории (можно абзац пропустить и не читать, тут выстраданное мною, поэтому не могу не написать :-).

Итак, не нужно загружать при помощи LoadLibrary стандартный плагин tmppanel.dll в память самому из своего плагина, нужно попросить сделать это FAR, тогда точно будет известно, что к моменту необходимости работы с "временной панелью" из своего плагина, она будет уже загружена в память и нужным образом проинициализирована. Для этого нужно, чтобы в tmppanel.dll выставлялся флаг PF_PRELOAD. В tmppanel.dll версии 1.70 build 27 (входит в релиз FAR 1.70) этот флаг не выставляется, поэтому я произвел все необходимые изменения в стандартном плагине и его версия 1.71 build 28 (ищите на официальном сайте) делает все, что нам нужно.

Вместо LoadLibrary мы получаем указатель на загруженную "временную панель" при помощи GetModuleHandle:

HMODULE hPluginDll=GetModuleHandle("TmpPanel.dll");

Соответственно, выгружать нам потом тоже ничего вручную не нужно.

Модуль tmppanel.dll экспортирует следующие функции: ClosePlugin, Configure, ExitFAR, GetFindData, GetMinFarVersion, GetOpenPluginInfo, GetPluginInfo, OpenFilePlugin, OpenPlugin, ProcessEvent, ProcessKey, PutFiles, SetDirectory, SetFindList, SetStartupInfo .

Нам потребуется задействовать все из них, за исключением SetStartupInfo, ExitFAR, GetPluginInfo, GetMinFarVersion, Configure, OpenFilePlugin, т.к. они представляют интерес только для самого FAR'а. Для получения адресов указанных функций используется GetProcAddress . У меня это выглядит приблизительно вот так:

typedef HANDLE (WINAPI *PLUGINOPENPLUGIN)(int OpenFrom,int Item);
typedef void (WINAPI *PLUGINCLOSEPLUGIN)(HANDLE hPlugin);
typedef void (WINAPI *PLUGINGETOPENPLUGININFO)(HANDLE hPlugin,
                                               struct OpenPluginInfo *Info);
typedef int (WINAPI *PLUGINPUTFILES)(HANDLE hPlugin,struct PluginPanelItem *PanelItem,
                                     int ItemsNumber,int Move,int OpMode);
typedef int (WINAPI *PLUGINGETFINDDATA)(HANDLE hPlugin,
                                        struct PluginPanelItem **pPanelItem,
                                        int *pItemsNumber,int OpMode);
typedef int (WINAPI *PLUGINSETDIRECTORY)(HANDLE hPlugin,const char *Dir,int OpMode);
typedef int (WINAPI *PLUGINSETFINDLIST)(HANDLE hPlugin,
                                        const struct PluginPanelItem *PanelItem,
                                        int ItemsNumber);
typedef int (WINAPI *PLUGINPROCESSKEY)(HANDLE hPlugin,int Key,
                                       unsigned int ControlState);
typedef int (WINAPI *PLUGINPROCESSEVENT)(HANDLE hPlugin,int Event,void *Param);

struct TEMPPANEL
{
  PLUGINOPENPLUGIN        OpenPlugin;
  PLUGINCLOSEPLUGIN       ClosePlugin;
  PLUGINSETFINDLIST       SetFindList;
  PLUGINPROCESSKEY        ProcessKey;
  PLUGINPROCESSEVENT      ProcessEvent;
  PLUGINGETOPENPLUGININFO GetOpenPluginInfo;
  PLUGINGETFINDDATA       GetFindData;
  PLUGINSETDIRECTORY      SetDirectory;
  PLUGINPUTFILES          PutFiles;
  BOOL Init(HMODULE hDll)
  {
    OpenPlugin=NULL;
    ClosePlugin=NULL;
    SetFindList=NULL;
    ProcessKey=NULL;
    ProcessEvent=NULL;
    GetOpenPluginInfo=NULL;
    GetFindData=NULL;
    SetDirectory=NULL;
    PutFiles=NULL;
    if(hDll)
    {
      OpenPlugin=reinterpret_cast(GetProcAddress(hDll,"OpenPlugin"));
      ClosePlugin=reinterpret_cast(GetProcAddress(hDll,"ClosePlugin"));
      SetFindList=reinterpret_cast(GetProcAddress(hDll,"SetFindList"));
      ProcessKey=reinterpret_cast(GetProcAddress(hDll,"ProcessKey"));
      ProcessEvent=reinterpret_cast(GetProcAddress(hDll, "ProcessEvent"));
      GetOpenPluginInfo=reinterpret_cast(GetProcAddress(hDll, "GetOpenPluginInfo"));
      GetFindData=reinterpret_cast(GetProcAddress(hDll, "GetFindData"));
      SetDirectory=reinterpret_cast(GetProcAddress(hDll, "SetDirectory"));
      PutFiles=reinterpret_cast(GetProcAddress(hDll, "PutFiles"));
    }
    return OpenPlugin && ClosePlugin && SetFindList && ProcessKey && ProcessEvent &&
           GetOpenPluginInfo && GetFindData && SetDirectory && PutFiles;
  }
};
...
HMODULE hPluginDll=GetModuleHandle("TmpPanel.dll");
// тут код проверки hPluginDll, на случай, если вызов GetModuleHandle
// окончился неудачей, вывод соответствующих сообщений и т.п.
TEMPPANEL TmpPanel;
if(TmpPanel.Init(hPluginDll))
{
  // если инициализация указателей на функции успешная
}
else
{
  // ...если облом
}

Чтобы добавить наши файлы на "временную панель" нужно получить указатель на эту самую панель при помощи TmpPanel.OpenPlugin, затем вызвать TmpPanel.SetFindList и, наконец, вернуть FAR'у указатель на созданную временную панель. Схематично выглядеть это будет вот так:

HANDLE WINAPI _export OpenPlugin(int OpenFrom, int Item)
{
  HANDLE retCode=INVALID_HANDLE_VALUE;
  ...
  PluginPanelItem *ppi=NULL; // тут будет перечень файлов, которые
                             // надо поместить на временную панель
  DWORD ppi_total=0;         // количество этих файлов
  ...
  if(ppi_total)
  {
    // TmpPanel мы инициализировали где-то раньше!
    HANDLE hTmp=TmpPanel.OpenPlugin(OPEN_FINDLIST,0);
    if(INVALID_HANDLE_VALUE!=hTmp)
    {
      // временная панель успешно создана,
      // теперь добавим в нее файлы
      if(!TmpPanel.SetFindList(hTmp, ppi, ppi_total))
      {
        // не удалось поместить файлы на панель,
        // закроем ее
        TmpPanel.ClosePlugin(hTmp);
        hTmp=INVALID_HANDLE_VALUE;
      }
      retCode=hTmp;
    }
    else
    {
      // создать временную панель не удалось
    }
  }
  ...
  return retCode;
}

Ну, и наконец, следует экспортировать все прочие функции, которые которые мы цепляем из tmppanel.dll (кроме SetFindList - зачем плодить сущности?!), в противном случае, пользователь не сможет полноценно работать с "временной панелью", открытой путем вызова нашего плагина. Код экспортируемых функций простейший:

void WINAPI ClosePlugin(HANDLE hPlugin)
{
  TmpPanel.ClosePlugin(hPlugin);
}

void WINAPI GetOpenPluginInfo(HANDLE hPlugin, struct OpenPluginInfo *Info)
{
  TmpPanel.GetOpenPluginInfo(hPlugin, Info);
}

int WINAPI GetFindData(HANDLE hPlugin, struct PluginPanelItem **pPanelItem,
                       int *pItemsNumber, int OpMode)
{
  return TmpPanel.GetFindData(hPlugin, pPanelItem, pItemsNumber, OpMode);
}

int WINAPI SetDirectory(HANDLE hPlugin,const char *Dir,int OpMode)
{
  return TmpPanel.SetDirectory(hPlugin, Dir, OpMode);
}

int WINAPI PutFiles(HANDLE hPlugin, struct PluginPanelItem *PanelItem,
                    int ItemsNumber,int Move, int OpMode)
{
  return TmpPanel.PutFiles(hPlugin, PanelItem, ItemsNumber, Move, OpMode);
}

int WINAPI ProcessEvent(HANDLE hPlugin, int Event, void *Param)
{
  return TmpPanel.ProcessEvent(hPlugin, Event, Param);
}

int WINAPI ProcessKey(HANDLE hPlugin, int Key, unsigned int ControlState)
{
  return TmpPanel.ProcessKey(hPlugin, Key, ControlState);
}


Это все, буду рад, если указанная статья поможет кому-то при написании собственного плагина.


 
15.04.2006

P.S. На момент написания данной статьи соответствующая версия S&R публично не доступна, т.к. находится все еще в стадии разработки. Следите за рекламой! :-)

наверх