- Q: Как мне спрятать курсор?
A: Windows API console API: SetConsoleCursorInfo, только не забудь его потом вернуть на место.
- Q: А как перевести в нужную позицию?
A: Там же: SetConsoleCursorPosition
- Q: Чтобы плагин работал и в редакторе и в shell (и на панели) что нужно ставить во флагах: Info->Flags=?????;
A: PF_EDITOR
- Q: Возможно динамическое отключение/подключение плагина не перезапуская FAR?
A: Да.
- Q: Плагины в редакторе срабатывают только при активизации? А можно ли сварганить такой, чтобы в фоновом режиме работал?
A: Можно. Экспортировать ProcessEditorInputW и ему будет приходить все нажатия клавиш в редакторе.
- Q: А можно в одном DLL-модуле держать несколько плагинов... Несколько функций, так сказать... И чтобы каждый вызывался, как будто бы находился в отдельном DLL-файле (пусть даже с полной загрузкой всего DLL`я)...
A: Да. В PluginInfo можно указать несколько строк, добавляемых к plugins menu. Но
это не является "хорошим тоном".
- Q: ...а потом различать что хотел пользователь по параметру Item в функции OpenPlugin?
A: Правильно.
- Q: Возможно ли при нынешнем API сделать плагин, работающий в фоновом режиме?
A: Разве что в редакторе. В панелях такое не поддерживается.
- Q: Есть файл, который можно открыть плагином. Могу ли я как-то об этом узнать? Лучше всего отдать команду на cd туда и получить ответ - смогли/не смогли.
A: Нет, api для взаимодействия между плагинами в FAR отсутствует. Тут одной проверкой на принадлежность файла не обойтись.
- Q: Как бы это из плагинового модуля получить полный путь до него самого?...
A: В функцию SetStartupInfoW far передаёт указатель на структуру PluginStartupInfo. Полное имя модуля содержится в поле ModuleName оной структуры.
- Q: Можно ли из плагина управлять переключением фоновых экранов FAR?
A: Можно.
- Q: А как FAR определяет, что в клипборде лежит именно вертикальный блок?
A: У вертикального блока clipboard format - "FAR_VerticalBlock"
- Q: Скажи, а что - никак нельзя узнать, на чём стоит курсор в текущей панели? Т.е. меня интересует - на каталоге или на файле...
A:Control(FCTL_GETPANELINFO);
Control(FCTL_GETPANELINFO);
PanelInfo.PanelItems[PanelInfo.CurrentItem].FindData.dwFileAttributes
- Q: Нельзя ли пpи перерисовке любой панели перерисовывать заголовок окна? По моему, это будет проще и быстрее, чем плагину вызывать FCTL_REDRAWPANEL.
A: Насчёт быстрее - не факт. Если заголовок не изменён плагином, как оно обычно и бывает, FAR перерисует его вхолостую.
- Q: Откуда FAR берёт процедуры для копирования/удаления/... файлов?
A: Из Windows API.
Копирование: CreateFile+ReadFile+WriteFile+CloseHandle или CopyFile(Ex), в зависимости от ОС и опции "Use system copy routine".
Удаление: DeleteFile или SHFileOperation в зависимости от опции "Delete to Recycle Bin"
- Q: Как можно получить имя каталога, из которого запущен FAR?
A: char lpName[_MAX_PATH], lpFullPath[_MAX_PATH];
LPTSTR lpFile;
GetModuleFileName(NULL,lpName,sizeof(lpName));
GetFullPathName(lpName,sizeof(lpFullPath),lpFullPath,&lpFile);
*lpFile='\0';
- Q: А как уменьшить размер DLL - уж больно "жирный" модуль получается?
A:
- В разделе "Статьи" есть несколько
заметок на эту тему.
- Плагинописателям, пишущим на Visual C++ и борющимся за уменьшение размера
плагинов, настоятельно рекомендуется прочитать:
https://msdn.microsoft.com/msdnmag/issues/01/01/hood/default.aspx (archive.org)
- Q: А что за дупы в клипборде идут, зачем 2 раза одну и ту же в Clipboard помещать?
A: Если поместить текст в clipboard в каком-то одном формате,
а программа просит его в другом, то Windows занимается перекодировкой
самостоятельно, и очень часто делает это коряво. Псевдографика портится,
иногда вместо русских букв остаются одни '?', конкретные глюки зависят
от версии Windows и комбинации исходного и запрашиваемого форматов.
Если же поместить все форматы сразу, то Windows находит нужный
и использует его без всяческих перекодировок.
- Q: Как определить что есть "связь каталогов" - простая ссылка на каталог или монтированный диск.
A: Основное правило - связи каталогов - ТОЛЬКО ДЛЯ КАТАЛОГОВ!
Значит нам нужно узнать - "А не каталог ли ЭТО?".
На это указывает файловый атрибут FA_DIREC (или
FILE_ATTRIBUTE_DIRECTORY).
Едем дальше.
Нам достоверно известно, что любые связи каталогов
имеют атрибут FILE_ATTRIBUTE_REPARSE_POINT - проверяем его.
Вызываем
FSF.GetReparsePointInfo(FullFolderName,DestName,sizeof(DestName))
Эта функция возвращает нам для некоторого заданного пути "FullFolderName"
некий реальный путь "DestName", который имеет суть:
"\??\D:\Junc..."
симлинк на каталог.
"\\?\Volume{..."
монтированный диск.
ПРИЧЁМ! Нас совершенно не интересуют первые 4 символа! Следовательно
достаточно сделать проверку 7 символов, начиная с четвёртого:
if(!strncmp(JuncName+4,"Volume{",7))
{
// это явно монтированный диск!
}
else
{
// простая ссылка на каталог
}
- Q: Да. Но ведь интересно знать, что скрывается по именем '\\?\Volume{...'?
A: Проще простого. Для этого вызовем функцию
FSF.GetPathRoot(JuncName,Root);
которая возвращает реальный корень в одной из двух реинкарнаций:
"D:\"
"\\?\Volume{..."
второй случай - "тяжёлый" :-) - здесь видимо на уровне системы (в
менеджере дисков) для данного диска удалили буковку... Ну, что бы не
маячила, т.с. ;-)
- Q: А ещё что нить полезного про символические ссылки можно узнать?
A: А как же :-) Правда не совсем про символические ссылки, но...
Например, мы можем узнать ещё порцию полезностей для монтированных
дисков. Здесь всё просто - вызываем стандартную
GetVolumeInformation()
Т.е. нам уже известен корень - "GetPathRoot(JuncName,Root);",
осталось получить информацию (например, возможности файловой системы
по поддержке расширенных атрибутов - сжатие и шифрование и тип файловой
системы):
DWORD FileSystemFlags;
char FSysName[MAX_PATH];
if (GetVolumeInformation(Root,NULL,0,NULL,NULL,
&FileSystemFlags,FSysName,sizeof(FSysName)))
{
if (FileSystemFlags & FILE_FILE_COMPRESSION)
{
// файловая система поддерживает сжатие файлов
}
if (FileSystemFlags & FILE_SUPPORTS_ENCRYPTION)
{
// файловая система поддерживает шифрование файлов
}
}
Типичная функция проверки возможности создания... жёстких ссылок
могла бы выглядеть так:
BOOL CanCreateHardLinks(char *TargetFile,char *HardLinkName)
{
char RootTarget[MAX_PATH],RootHardLink[MAX_PATH],FSysName[MAX_PATH];
GetPathRoot(TargetFile,RootTarget);
GetPathRoot(HardLinkName,RootHardLink);
if(!strcmp(RootTarget,RootHardLink)) // тот же корень (то же диск)?
{
DWORD FileSystemFlags;
if(GetVolumeInformation(RootTarget,NULL,0,NULL,NULL,&FileSystemFlags,
NULL,0))
{
if(FileSystemFlags&FILE_SUPPORTS_HARD_LINKS)
return TRUE;
}
}
return FALSE;
}
- Q: Можно ли получить для редактируемого файла флаг изменён/неизменен? Я сходу не нашёл, а ведь FAR это знает, звёздочку в верхней строке показывает.
A: См. описание структуры EditorInfo,
конкретно значения поле EditorInfo.CurState.
- Q: Как узнать имя файла, загруженного во вьюер?
A: Вот такой вот код запросто узнаёт текущее имя в программе просмотра:
WindowInfo wi;
wi.Pos=-1;
Info.AdvControl(Info.ModuleNumber,ACTL_GETWINDOWINFO,&wi);
всё. в wi.Name лежит имя файла.
- Q: Возможно ли каким-то способом в FSF.ProcessName, при сравнении маски "OUTBOUND\\????????.MO?" и файла
"С:\\FILES\\OUTBOUND\\0000ee2c.mod" получить TRUE,
а с файлом "C:\\MUSIC\\assol_1.mod" обломаться?
PN_SKIPPATH не подходит. При наличии "\\" в маске он, похоже, никогда не вернёт TRUE.
A: Сравнивай с маской "*\\OUTBOUND\\????????.MO?" без использования
PN_SKIPPATH.
- Q: Как Windows "сбрасывает" имя файла из Проводника в консольное окно?
A:
Vasily Titsky: "...Если кратко, то когда в консольное приложение идёт вставка текста
(через системное меню, или кидая ярлык) то добрая ОС делает вот что:
если в текущем Keyboard Layout приложения и очередной код символа не пересекаются
(текущий язык - english, а вставлять надо символ русского алфавита; или наоборот),
то она "эмулирует" ввод этого символа через Alt+цифры. Например, при вставке русской
'А' , будет сгенерировано: нажатие Alt, нажатие '1', отпускание '1', нажатие '2', отпускание '2',
нажатие '8', отпускание '8', отпускание Alt.
При вставке символов с кодом, меньшим 99 (? - не проверял) имитируется
нажатие 2-х цифр. Остаётся только правильно это обнаружить и обработать..."
- Q: Почему-то не работает ProcessKey?
Пишу в Delphi:
function ProcessKey(hPlugin: THandle; Key: Integer; ControlState: Word): integer; stdcall;
begin
windows.Beep(300,200);
//возвращаем False для дальнейшей обработки FARом
result:=0;
end;
По идее должен выдаваться сигнал при любом нажатии клавиши - этого не происходит. То же самое, если делаю это для какой-то конкретной клавиши.
A: FAR вызывает функцию ProcessPanelInputW для активной плагиновой панели.
- Q: Можно ли из плагина перейти на определённый файл в директории?
A:
{
struct PanelInfo PInfo;
Info.PanelControl(INVALID_HANDLE_VALUE,FCTL_GETPANELINFO,&PInfo);
// установить позицию на элементе панели selectItem
struct PanelRedrawInfo PRI;
char Name[MAX_PATH], Dir[MAX_PATH*5];
int pathlen;
strcpy(Name,Info.FSF->PointToName(selectItem));
pathlen=Info.FSF->PointToName(selectItem)-selectItem;
if(pathlen)
memcpy(Dir,selectItem,pathlen);
Dir[pathlen]=0;
Info.FSF->Trim(Name);
Info.FSF->Trim(Dir);
Info.FSF->Unquote(Name);
Info.FSF->Unquote(Dir);
if(*Dir)
Info.PanelControl(INVALID_HANDLE_VALUE,FCTL_SETPANELDIR,&Dir);
Info.PanelControl(INVALID_HANDLE_VALUE,FCTL_GETPANELINFO,&PInfo);
PRI.CurrentItem=PInfo.CurrentItem;
PRI.TopPanelItem=PInfo.TopPanelItem;
for(int J=0; J < PInfo.ItemsNumber; J++)
{
if(!Info.FSF->LStricmp(Name,Info.FSF->PointToName(PInfo.PanelItems[J].FindData.cFileName)))
{
PRI.CurrentItem=J;
PRI.TopPanelItem=J;
break;
}
}
Info.PanelControl(INVALID_HANDLE_VALUE,FCTL_REDRAWPANEL,&PRI);
}
- Q: Как из плагина запустить что-нибудь? И как показать вывод этой программы под панелями?
A:
Info.PanelControl(INVALID_HANDLE_VALUE,FCTL_GETUSERSCREEN,NULL);
if (CreateProcess(NULL,"ls.exe",NULL,NULL,TRUE,0,NULL,NULL,&si,&pi))
{
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
Info.PanelControl(INVALID_HANDLE_VALUE,FCTL_SETUSERSCREEN,NULL);