Подмена "штатного" сетевого окружения при возврате с хоста
Select messages from
# through # FAQ
[/[Print]\]

Total Commander -> Написание плагинов для Total Commander

#1: Подмена "штатного" сетевого окружения при возврате с хоста Author: HankHank PostPosted: Thu Apr 15, 2010 16:48
    —
Привет присутствующим.

Есть непростой вопросец для работы с удалённым компьютером.
Предположим, что переходим к удалённому хосту командой типа:
cd \\<IP-адрес или NetBIOS -имя> ,
задавая её в командной строке Коммандера.
Поработав на удалённом хосте, “возвращаемся назад”, многократно щёлкая кнопкой мыши или нажимая Enter на [..] (возврат на уровень вверх). Когда достигаем самого “верхнего уровня” хоста, по умолчанию (?) возвращаемся в “штатное” сетевое окружение Коммандера.

Есть ли способ вызвать подменой (либо как-то иначе) другой плагин (или кнопку, или команду) вместо “штатного” сетевого окружения ?

Есть решение с помощью AHK. Но оно не устраивает.

#2:  Author: HankHank PostPosted: Fri Apr 16, 2010 10:03
    —
Буду благодарен за любые мысли вслух, пусть даже фантастические, чтобы выявить направления поиска...

#3:  Author: RodnyLocation: Могилёв, Беларусь PostPosted: Fri Apr 16, 2010 10:58
    —
HankHank
Quote:
Есть ли способ вызвать подменой (либо как-то иначе) другой плагин (или кнопку, или команду) вместо “штатного” сетевого окружения ?

Не совсем понятно, что ты хочешь.
Чтобы кнопка "Сеть / FS-плагины" имела другую функцию? Нет, нельзя.
Кнопку/команду для перехода в определённый плагин? Пожалуйста, "cd \\\Плагин"

#4:  Author: HankHank PostPosted: Fri Apr 16, 2010 11:16
    —
Rodny wrote:
Не совсем понятно, что ты хочешь.
Чтобы кнопка "Сеть / FS-плагины" имела другую функцию? Нет, нельзя.

Объясняю ещё раз.
После выхода из хоста, на который зашли по команде cd \\<имя хоста или его IP>, Коммандер выбрасывает пользователя не в окно, как ты пишешь "Сеть / FS-плагины" , а в сетевое окружение Коммандера. Я его условно называю "штатным". По сути, - это рабочая группа, полученная через механизм броузера Windows. Как это окно формируется Гислером, это тоже возможный путь для моей "подмены". Но я реализации пока не понимаю.

Вот ЕСТЬ НУЖДА МИНОВАТЬ ЭТО "ШТАТНОЕ", а перейти в другое АВТОМАТИЧЕСКИ - по команде, подменой кода или каким-то иным способом. Под "другим" окружением я разумею плагин, который можно вызвать перечисленными способами. Поэтому я и призываю спецов и любителей хотя бы пофантазировать на заданную тему, если отсутствует готовое решение.

Есть способ перехвата момента появления штатного окружения с помощью скрипта, о чём я написал ранее. Но получается некрасиво, долго, в целом - непрофессионально.

Так понятнее задача ?
Коротко она звучит так: "Отловить момент возврата из хоста и автоматичи передть управление не на штатное сетевое окружение, а на другой исполняемый код".


Last edited by HankHank on Fri Apr 16, 2010 11:26; edited 1 time in total

#5:  Author: alexey65536Location: Taganrog PostPosted: Fri Apr 16, 2010 11:26
    —
Т.е., допустим, нажав [..] в корне хоста \\COMP, я должен попадать не в WORKGROUP/MSHOME/что-то еще, а в произвольное место (плагин и т.п.)?

#6:  Author: HankHank PostPosted: Fri Apr 16, 2010 11:27
    —
Так точно !

#7:  Author: MVVLocation: Ростов-Дон PostPosted: Fri Apr 16, 2010 17:04
    —
Объясню то, что написал на оф. форуме, но по-русски. Если ты обрабатываешь в хуке сообщения клавы и мыши, ты можешь удалять невыгодные тебе сообщения (обычно в конце хук-обработчика нужно вызывать CallNextHookEx, но в этих обработчиках можно просто вернуть ненулевое значение - и сообщение дальше твоего хука не пойдет). Т.е. ты ловишь попытку юзера нажать Enter или сделать двойной щелчок на элементе ".." до того как ТК получит это сообщение и, если видишь, что при таком раскладе юзер попадет в Сетевое окружение, просто удаляешь сообщение, а ТК говоришь перейти в нужный тебе каталог. В итоге ТК вообще не узнает о том, что юзер хотел зайти в Сетевое окружение.

Ловить двойной щелчок или нажатие Enter несложно, далее просто получаешь индекс текущего элемента - если ноль, значит, это элемент "..". Далее, если ноль (если не ноль, надо вызывать следующий обработчик и не тормозить систему лишний раз), начинаешь проверять текущий путь - например, как я писал, получаешь его из поля строки состояния (при инициализации плагина один раз получаешь его дескриптор и запоминаешь - он не изменится до закрытия ТК) и определяешь, верхний ли это уровень. Если да - действуешь.

#8:  Author: HankHank PostPosted: Fri Apr 16, 2010 22:00
    —
Чёрт побери, приятная неожиданность, MVV ! Где только не встретишь наших людей ! Very Happy
Да ещё и сподобиться получить ответ от Гислера в тот же день. Хотя, по сути - пустой ответ. Но мы не ищем лёгких путей.

MVV wrote:
Если ты обрабатываешь в хуке сообщения клавы и мыши, ты можешь удалять невыгодные тебе сообщения ...

Да, я понял мысль - написать собственный обработчик, о чём не имею понятия. Но тогда встаёт в полный рост вопрос:
Can you recommend samples of ready templates with a code of a similar trap for M$ Visual C++ ?

#9:  Author: MVVLocation: Ростов-Дон PostPosted: Fri Apr 16, 2010 22:16
    —
HankHank wrote:
Где только не встретишь наших людей ! Very Happy

Наши везде пролезутSmile Я тут видел твое сообщение до того, как увидел там - поэтому понял, что то - твой пост, и отписался тут.

HankHank wrote:
Да ещё и сподобиться получить ответ от Гислера в тот же день. Хотя, по сути - пустой ответ.

Согласись, его можно понять - ты предлагаешь хардкодить граблиSmile

В общем, я набросал тебе пример, выложил в теме на оф. сайте.
Для экспериментов сделал копию папки проекта своей VP и извращался с ней. Very Happy
Вроде все работает. Хук-функции получились маленькие, работать будут быстро, тем более, быстрые отсекающие проверки делаются в первую очередь. Вопросы, комментарии - вэлкам.

Как я уже советовал там, лучше при переходе из плагина по сетевому пути запоминать его корневую папку (имя сервера) - и при 'подъеме' проверять, на этом ли серваке юзер (а то может он уже ушел гулять по другим, а ты ему будешь малину портить).
Кстати, в настройках своего плагина сделай опцию отключать эти извращения - хуки можно не вырубать, а при входе в них сразу проверяй флаг и выходи из хук-функции (не забудь вызывать CallNextHookEx) - проще всего добавить условный блок верхнего уровня, внутри которого проверяются и обрабатываются сообщения. То есть, юзер отключил фишку - сразу вызываешь следующий хук.

#10:  Author: HankHank PostPosted: Fri Apr 16, 2010 23:16
    —
Сердечная благодарность за помощь. На неделе попытаюсь разобраться и прикрутить. Вопросы наверняка появятся.
Хороших выходных !

#11:  Author: VadiMGP PostPosted: Sun Apr 18, 2010 01:41
    —
MVV
Я детально не штудировал твой пример, но две проблемы сразу заметны. Они касаются листбоксов (mylb1 и mylb2).
1. Ты исходишь из предположения, что в ТС всегда 2 листбокса. Но это не так. Окна с деревьями тоже листбоксы, значит в разное время может быть от 2 до 4 листбоксов.
2. Ты берешь HWND от них только один раз при инициализации. Но ТС часто уничтожает и создает листбоксы динамически. Например при переключении между режимами (подробный, эскизы, пользовательские колонки).

#12:  Author: MVVLocation: Ростов-Дон PostPosted: Sun Apr 18, 2010 10:24
    —
VadiMGP wrote:
Я детально не штудировал твой пример, но две проблемы сразу заметны. Они касаются листбоксов (mylb1 и mylb2).

Что ж, я не давал клятву, что он идеален. Smile

VadiMGP wrote:
1. Ты исходишь из предположения, что в ТС всегда 2 листбокса. Но это не так. Окна с деревьями тоже листбоксы, значит в разное время может быть от 2 до 4 листбоксов.

Да, действительно. Но я заметил, что у листбоксов деревьев имя текст окна не пуст, значит, можно искать окна файловых панелей по пустому тексту. Тогда в моем примере надо чуть изменить (указать не любой, а пустой текст окна при поиске):
Code:
   mylb1=FindWindowEx(hMainWnd, 0, L"TMyListBox", L"");
   mylb2=FindWindowEx(hMainWnd, mylb1, L"TMyListBox", L"");

Так мы гарантированно найдем окна панелей. Кстати, по идее можно просто брать активное окно, а не искать их - оно будет листбоксом при щелчке мышью и нажатии клавиш в интересующий нас момент.

VadiMGP wrote:
2. Ты берешь HWND от них только один раз при инициализации. Но ТС часто уничтожает и создает листбоксы динамически. Например при переключении между режимами (подробный, эскизы, пользовательские колонки).

Подтверждаю. Тоже не учел. В таком случае нужно либо искать окна панелей каждый раз (два окна найти - не проблема), а можно просто использовать указанный выше фокус. То есть, вызываем GetFocus(), и если окно с фокусом - TMyListBox, значит, берем из него индекс и т.д. Панель состояния в любом случае не изменяется.

Итак, убираем дескрипторы mylb1, mylb2 и их поиск, а функцию GetActivePanel модифицируем следующим образом:
Code:
HWND GetActivePanel() {
   HWND hwnd=GetFocus();
   wchar_t buf[256];
   if (!GetClassName(hwnd, buf, TSIZE(buf)) || lstrcmp(buf, L"TMyListBox")) return 0;
   if (GetWindowText(hwnd, buf, TSIZE(buf)) || GetLastError()) return 0;
   return hwnd;
}

Ну а в хук-функциях проверять, не ноль ли дескриптор окна - если ноль, ниче не делать.

#13:  Author: VadiMGP PostPosted: Sun Apr 18, 2010 11:01
    —
Еще одна проблема - будет ложное срабатывание в режиме эскизов.
Если в строке, скажем, 3 эскиза, то LB_ITEMFROMPOINT вернет 0 для любого из этих трех эскизов, а не только для "..".

Добавлено. Пригляделся еще раз. Нет, похоже, не будет вообще срабатывания. В функции IsForbiddenLevelUp GetWindowText не даст текста. В режиме эскизов невозможно получить текст элемента.

#14:  Author: MVVLocation: Ростов-Дон PostPosted: Sun Apr 18, 2010 12:29
    —
В функции IsForbiddenLevelUp я беру текст из панели в строке состояния, текст в которой есть независимо от режима панели. Текст элементов я вообще нигде не пытаюсь получить - он мне не нужен, расчет на то, что элемент ".." всегда имеет индекс 0.

А сообщение LB_ITEMFROMPOINT по идее должно возвращать индекс с учетом того, что листбокс может иметь несколько колонок или строк. Ты проверял, как работает LB_ITEMFROMPOINT, или это предположение?

Да, похоже, в режиме эскизов LB_ITEMFROMPOINT работает неправильно - действительно возвращает номер строки. Как, кстати, и LB_GETCARETINDEX - видимо, этот режим Гислер реализовывал сам, и об этих сообщениях не позаботился. Так что оба хука - и клавы, и мыши - будут срабатывать в режиме эскизов на всех элементах первой строки содержимого панели. Нужно что-то придумывать дополнительно.


Last edited by MVV on Sun Apr 18, 2010 12:49; edited 4 times in total

#15:  Author: VadiMGP PostPosted: Sun Apr 18, 2010 12:37
    —
MVV wrote:
В функции IsForbiddenLevelUp я беру текст из панели в строке состояния,
А, значит я ошибся насчет этого.
MVV wrote:
А сообщение LB_ITEMFROMPOINT по идее должно возвращать индекс с учетом того, что листбокс может иметь несколько колонок или строк.
По идее, конечно. Я тоже в свое время на это рассчитывал.
MVV wrote:
Ты проверял, как работает LB_ITEMFROMPOINT, или это предположение?
Еще как проверял. Я знаешь, как в TWinKey нажрался проблем с эскизами... Мама не горюй.

#16:  Author: VadiMGP PostPosted: Sun Apr 18, 2010 12:50
    —
MVV wrote:
В функции IsForbiddenLevelUp я беру текст из панели в строке состояния, текст в которой есть независимо от режима панели.

Тогда может быть другое ложное срабатывание - при выходе из виртуальной папки. Если, к примеру, ты в Control Panel, то текст панели будет "\\Control Panel\*.*".

#17:  Author: MVVLocation: Ростов-Дон PostPosted: Sun Apr 18, 2010 14:34
    —
VadiMGP wrote:
MVV wrote:
В функции IsForbiddenLevelUp я беру текст из панели в строке состояния, текст в которой есть независимо от режима панели.

Тогда может быть другое ложное срабатывание - при выходе из виртуальной папки. Если, к примеру, ты в Control Panel, то текст панели будет "\\Control Panel\*.*".

Вообще-то, конечно, "\\Панель управления>", но это детали. На этот счет я рекомендовал запоминать имя папки верхнего уровня и действовать только в том случае, если оно не изменилось - моя задача была раскрыть общую идею того, как работать с хуками.

#18:  Author: VadiMGP PostPosted: Sun Apr 18, 2010 14:55
    —
MVV wrote:
Вообще-то, конечно, "\\Панель управления>", но это детали.
Это, разумеется, детали, хотя у меня стоит имено "\\Control Panel\*.*". Smile
В любом случае, я вовсе не отвергаю идею, как таковую, я лишь указываю на некоторые подводные камни, об которые сам бился.

#19:  Author: MVVLocation: Ростов-Дон PostPosted: Sun Apr 18, 2010 21:48
    —
Тут проблема действительна для любой виртуальной папки вообще, так что панель управления - лишь пример.

А под деталями я имел в виду не то, что панель по-русски, а то, что в конце стоит знак больше, а не слэш и звездочка точка звездочка (я ведь беру текст из строки состояния, а не из панели пути).

#20:  Author: HankHank PostPosted: Mon Apr 19, 2010 10:02
    —
Привет, MVV.

Написанное тобой только слегка подрихтовал под Visual c 6.0: в функциях, содержащих L”…, перешёл с обнобайтовым строкам, и двухбайтовые char-типы соответственно заменил на char).
Небольшая описЬка в
Code:

bool IsForbiddenLevelUp()
{
   char buf[1024];
   GetWindowText(stpath, buf, TSIZE(buf));
   if (*(int*)buf!='\\\0\\' || buf[2]=='\\')


Заменена на
Code:

bool IsForbiddenLevelUp()
{
   char buf[1024];
   GetWindowText(stpath, buf, TSIZE(buf));
   if (!((buf[0]=='\\' && buf[1]=='\\') || buf[2]=='\\'))



и… всё заработало почти с пол-оборота. Отдаю должное профессиональной прозрачности написанного кода. И всё это – при вполне удовлетворительной скорости.

Поразмыслив о твоём предложении запрограммировать контроль, когда находимся “в среде моего плагина” – работает хук, вышли – хук сбросить, пришёл к выводу, который озвучивал ранее:
- возможны коллизии, когда в обеих панелях сетевая среда,
- моя “сетевая среда” была создана плагином, вышли из него, но вошли через командную строку, написав ту же магическую строчку cd \\< IP или имя>.
Поэтому решил оставить хук работающим после вызова плагина – хуже не будет.

Остались несколько мелких вопросов:
1. Поскольку имитируем ввод в командную строку “забивкой в клавиатуру” Коммандеру:
Code:

void DoMyAction()
{
   // focus to command line
   SendMessage(hMainWnd, WM_USER + 51, 4003, 0);
   // type of plugin
   SetWindowText(GetFocus(), "cd \\\\\\net");
   // ENTER-pressing
   keybd_event(VK_RETURN, 0, KEYEVENTF_EXTENDEDKEY, 0);
}
,
то в командной строчке успевает мелькнуть пресловутый вызов “cd \\\net”.

Нет ли другого способа “невидимого” вызова пллагина, чтобы “погасить” cd \\\net ?

2. При нахождении “в среде плагина” попытка ввести “cd \\< IP или имя>” не приводит к успеху – надо слегка подриххтовать логику. Ты, впрочем, об этом вскользь уже говорил.

3. До сего момента руки не доходили разобраться с вызовом плагина, как DLL-библиотеки. Поэтому был слегка озадачен, когда увидел, что вызов
Code:

BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)

происходит несколько раз (!) с параметрами ul_reason_for_call 1 и 2 – запуск самого процесса и первого его TREAD'а. Меня, собственно интересовал момент с условием
Code:

ul_reason_for_call==DLL_PROCESS_DETACH
, которого я так и не увидел.
Интересно, при каких условиях Гислер выдаёт такой параметр ? Или этот момент целиком на откупе у операционной системы ?

4. И последнее. Поскольку уже много лет, как профессионально не занимаюсь программированием, инструментарий у меня – дедовский – 6-я версия Visual’а.
Пробовал как-то из любопытства установить MS Visual 2005-ый из журнального диска – “Trial Express”, так был сильно разочарован. Внешне “верстак” выглядит красивее, чем в 6-ке, но в сущности – мЕньшая функциональность, ужасные объёмы базы MSDN. При том, что этот монстр ставится на комп довольно долго. И сносится также весьма небыстро. С месяц-два назад в Сети проходила инфо о выпуске Visual 2010- го.
Что говорят профи ? И, кстати, на чём работает Гислер ?

------------------------
Обновив страничку, увидел, что подключились ещё спецы с комментариями. За что участникам обсуждения – гран мерси.
Немного позже попробую внести соответствующие изменения.

С уважением.

#21:  Author: MVVLocation: Ростов-Дон PostPosted: Mon Apr 19, 2010 10:59
    —
Описек не было. Я писал для Юникод-версии, поэтому везде буквы L. А условие (*(int*)buf!='\\\0\\') эквивалентно тому, что первые два юникод-символа буфера равны слэшу (т.е., байты идут 5C 00 5C 00, что соответствует константе 0x005C005C, или '\\\0\\', хранящейся в первых 4 байтах буфера). Но согласен, твой вариант понятнее (признаю, есть у мя некая извратомания).

Скорость куды больше, чем в системном хуке от AHK. Very Happy


Менять путь, посылая сообщение установки текста полю пути - извращение и маразм. ТК поддерживает специальное оконное сообщение WM_COPYDATA, в котором можно послать путь для перехода. Но надо это делать в фоновом потоке (у меня из плагина не работало, если в основном).

Code:
DWORD __stdcall BackgroundSendData(void* Data) {
   auto_ptr<byte> ash((byte*)Data);
   SendMessage(hMainWnd, WM_COPYDATA, 0, (LPARAM)Data);
   return 0;
}

bool ChangeCurrentDir(const wchar_t* Path, bool NewTab) {
   int length=lstrlen(Path);
   auto_ptr<char> ash(new char[sizeof(COPYDATASTRUCT)+20+2*length]);
   COPYDATASTRUCT* cds=(COPYDATASTRUCT*)ash.get();
   char* data=ash.get()+sizeof(COPYDATASTRUCT);

   cds->dwData='DC';
   cds->lpData=data;
   char* p=data;
   if (Unicode) p+=wsprintfA(p, "\xEF\xBB\xBF");
   p+=WideCharToMultiByte(Unicode ? CP_UTF8 : CP_ACP, 0, Path, length, p, 2*length, 0, 0);
   p+=wsprintfA(p, "\r%cS%s", 0, NewTab ? "T" : "");
   cds->cbData=p-data+1;

   HANDLE thread=CreateThread(0, 0, &BackgroundSendData, ash.release(), 0, 0);
   if (!thread) return 0;

   CloseHandle(thread);
   return 1;
}

Первая функция посылает сообщение WM_COPYDATA, используя переданный ей указатель. Вторая формирует правильное сообщение и вызывает первую в фоновом потоке. То есть, в DoMyAction просто вызываешь ChangeCurrentDir, передав ей путь. Функция ChangeCurrentDir юникодная (опять же, выдрал из исходника VirtualPanel), при использовании юникода (у меня глобальная переменная Unicode при инициализации плагина ставится в 1, если вызывается FsInitW) посылает путь в UTF-8. Параметр NewTab тебе скорее всего не понадобится.


При первой подгрузке к процессу библиотеки функцией LoadLibrary система вызывает DllMain с fdwReason=DLL_PROCESS_ATTACH. Далее, при последующих вызовах LoadLibrary - с DLL_THREAD_ATTACH (заметил, что с таким значением вызывается неоднократно, так что лучше код туда не пихать). Значение DLL_PROCESS_DETACH передается в DllMain при выгрузке последней инстанции библиотеки из процесса - при закрытии ТК или при вызове команды cm_UnloadPlugins (частенько юзаю при отладке или для обновления плагина без перезапуска ТК). Это система делает при последнем вызове FreeLibrary (или же, по идее, при выгрузке процесса, загрузившего библиотечку - тут не знаю, вызовет ли, или молча убьет). К вызову DllMain Гислер отношения не имеет. Все, что ему нужно вызывать - LoadLibrary и FreeLibrary, а потом GetProcAddress для получения адресов экспортируемых функций плагина.


Мне лично больше нравятся 2005-2008 студии, чем 6, в них проблем с юникодом меньше (при установке свойств проекта или отладке, например - можно читать юникод-строки из Watch), лучше оптимизация (например, в реализации стандартной библиотеки "шестерки" дерево чистится путем удаления диапазона от начала до конца дерева - убиться веником, это ж тьма времени на поиск и удаление каждого элемента в отдельности, а в 2005 - умная функция рекурсивного удаления поддеревьев), приспособленность к новым системам. Очень люблю аддон VisualAssist (красит код, удобные функции, правда, триал на месяц, но есть RTKF). Express-версии студии, насколько я понимаю, не имеют PlatformSDK, т.е. могут не иметь нужных заголовочных файлов (не знаю, не ставил). Да, еще удобство в 2005 и выше - скрываемые боковые панели, очень экономит рабочее пространство. 2010 сам хочу попробовать, как будет возможность. Надеюсь, он не будет вешать мою семерку при отладке, как 2008-я (да, есть такое, причем наглухо и при пока непонятных обстоятельствах). Где можно, юзаю 2005-2008, где нельзя - 6 без установки, она справляется с компиляцией моего плагина (хотя Boost уже не тянет).


Гислер пишет ТК на второй дельфе. И я его понимаю. Чем выше версия дельфи, тем больше весит пустой проект (на шестой - в два раза больше, чем в третьей!) - и компоненты. А если не использовать эти извращения, то и второй вполне достаточно. Единственное что хороший компилятор бы ему не помешал наверняка (оптимизация и всё такое), но я не знаю, есть ли для дельфи хорошие компиляторы.

#22:  Author: HankHank PostPosted: Mon Apr 19, 2010 15:58
    —
MVV wrote:
Менять путь, посылая сообщение установки текста полю пути - извращение и маразм. ТК поддерживает специальное оконное сообщение WM_COPYDATA, в котором можно послать путь для перехода. Но надо это делать в фоновом потоке (у меня из плагина не работало, если в основном)...

Дык я тоже чувствую, что как-то уж очень топорно получается. Должен быть выход. Попробовал приладить код с вызовом фонового процесса, получилось так:
Code:

DWORD __stdcall BackgroundSendData(void* Data)
{
   SendMessage(hMainWnd, WM_COPYDATA, 0, (LPARAM) Data);
   return 0;
}

bool ChangeCurrentDir()
{
   COPYDATASTRUCT cds;
   char buffer[]="cd \\\\\\net";
   cds.dwData='DC';
   cds.lpData=&buffer;
   cds.cbData=sizeof(buffer);

   HANDLE thread=CreateThread(0, 0, &BackgroundSendData, &cds, 0, 0);
   if (!thread) return 0;

   CloseHandle(thread);
   return 1;
}

Компиллятор не взбрыкнул. Нужный процесс рождается. Код возврата thread ненулевой. Но эффекта - нет. Так и стоим на месте - на [..]. Подробнее пока не глядел.
Может, свежим взглядом косяк виден сразу ?

И ещё немного оффтопа.
1. Поскольку в основном эксплуатирую всякий софт, а не занимаюсь разработкой, то отстал от жизни. Не очень понимаю перспективы 64-битной судьбы Коммандера. В Сети встречал рассуждения, что, вроде бы для TC особой нужды нет в переходе на 64-ю платформу. Как 32-битное приложение TC вполне справляется со всеми практическими задачами. Мол, есть системные папки под Windows 7, которые напрямую сейчас не доступны, но к ним TC доступ обеспечивает, тем не менее.

2. Также интересен вопрос UNICODE под TC. Ещё в примере реализации FS-плагина TC я обратил внимание на функции API TC, содержащие буковку "w". Насколько учёт UNICODE оказывает практическое влияние на разработку плагинов под TC ? Так ли нельзя без него обойтись ?

#23:  Author: AvadaLocation: Россия, Саратов PostPosted: Mon Apr 19, 2010 16:33
    —
HankHank wrote:
И ещё немного оффтопа.

А вот этого не надо. Правила форума существуют для того, чтобы их соблюдали.
Ответ на первый вопрос — например, здесь. Или здесь. Второй вопрос имеет смысл прояснять в подфоруме по разработке плагинов, к "Общим вопросам" он никак не относится.

#24:  Author: MVVLocation: Ростов-Дон PostPosted: Mon Apr 19, 2010 18:04
    —
HankHank wrote:
Попробовал приладить код с вызовом фонового процесса, получилось так:
Code:

...

Компиллятор не взбрыкнул. Нужный процесс рождается. Код возврата thread ненулевой. Но эффекта - нет. Так и стоим на месте - на [..]. Подробнее пока не глядел.
Может, свежим взглядом косяк виден сразу ?

Ну молодец! Так и до вылета ТК в трубу недалеко. Very Happy

А теперь поясняю, что у тебя происходит. Ты выделил в стеке место для буфера и вписал в него путь. Далее, ты вызываешь фоновую функцию и передаешь ей адрес этого буфера, и не дожидаясь ее завершения выходишь из функции, в которой буфер был выделен, то есть, уничтожаешь его! Что будет? Система при отправке сообщения WM_COPYDATA скопирует указанное число байт по указанному адресу в свой буфер (заметь, там уже может быть что угодно, так как основной поток продолжает работать и использовать стек по своему усмотрению) и отправит сообщение ТК, указав новый адрес буфера (функция позволяет передавать буфера между процессами, поэтому она переписывает данные в буфер в адресном пространстве процесса-получателя). Итак, ТК просто получит мусор. Но хрен его знает, насколько правильно он этот мусор интерпретирует.

Выход? Выделять память динамически. Ты убрал юникод из функции - да, это тебе не нужно. Но советую вернуть назад динамическое выделение памяти, без него передавать что-либо в другой поток не советую. В моих функциях память выделялась динамически и передавался указатель на выделенный буфер, который затем освобождался функцией в фоновом потоке.

Еще один момент - плагин у юзера необязательно будет называться "net", имя можно дать любое в настройке FS-плагинов.


Кстати, заметил, что у меня может теряться память, если будет ошибка создания фонового потока. Модернизировал:
Code:
struct BackgroundSendDataData {
   COPYDATASTRUCT CopyData;
   char Raw[0];
};

DWORD __stdcall BackgroundSendData(void* Data) {
   BackgroundSendDataData* bsd=(BackgroundSendDataData*)Data;
   auto_ptr<char> ash((char*)Data);
   SendMessage(hMainWnd, WM_COPYDATA, 0, (LPARAM)&bsd->CopyData);
   return 0;
}

bool ChangeCurrentDir(const wchar_t* Path, bool NewTab) {
   int length=lstrlen(Path);
   auto_ptr<char> ash(new char[sizeof(BackgroundSendDataData)+20+2*length]);
   BackgroundSendDataData* bsd=(BackgroundSendDataData*)ash.get();

   bsd->CopyData.dwData='DC';
   bsd->CopyData.lpData=bsd->Raw;
   char* p=bsd->Raw;
   if (Unicode) p+=wsprintfA(p, "\xEF\xBB\xBF");
   p+=WideCharToMultiByte(Unicode ? CP_UTF8 : CP_ACP, 0, Path, length, p, 2*length, 0, 0);
   p+=wsprintfA(p, "\r%cS%s", 0, NewTab ? "T" : "");
   bsd->CopyData.cbData=p-bsd->Raw+1;

   HANDLE thread=CreateThread(0, 0, &BackgroundSendData, ash.get(), 0, 0);
   if (!thread) return 0;

   ash.release();
   CloseHandle(thread);
   return 1;
}

(заодно сделал структуру буфера более понятной - вначале идет COPYDATASTRUCT, а сразу за ней - буфер произвольной длины, адрес и размер которого она содержит)

И ANSI-версия ChangeCurrentDir (вроде так, проверить нет времени; функция фонового потока общая):
Code:
bool ChangeCurrentDir(const char* Path, bool NewTab) {
   int length=lstrlen(Path);
   auto_ptr<char> ash(new char[sizeof(BackgroundSendDataData)+20+length]);
   BackgroundSendDataData* bsd=(BackgroundSendDataData*)ash.get();

   bsd->CopyData.dwData='DC';
   bsd->CopyData.lpData=bsd->Raw;
   char* p=bsd->Raw;
   p+=wsprintf(p, "%s\r%cS%s", Path, length, 0, NewTab ? "T" : "");
   bsd->CopyData.cbData=p-bsd->Raw+1;

   HANDLE thread=CreateThread(0, 0, &BackgroundSendData, ash.get(), 0, 0);
   if (!thread) return 0;

   ash.release();
   CloseHandle(thread);
   return 1;
}



На оффтоп отвечать не буду, раз модераторы против. Хотя, могу в личку.


HankHank wrote:
При нахождении “в среде плагина” попытка ввести “cd \\< IP или имя>” не приводит к успеху – надо слегка подриххтовать логику. Ты, впрочем, об этом вскользь уже говорил.

Заметил этот абзац - и возник вопрос. Ты вводишь команду для перехода в сетевую папку, находясь в папке плагина, и оно не работает (в ТК команда cd не работает в папках FS-плагинов; ты должен вручную реализовать обработку команды cd и изменить текущую папку - например, вызвав ChangeCurrentDir, как делает моя VirtualPanel), или ты пытаешься обойти хук с помощью команды cd (я говорил как раз об этом - не нужно блокировать команду cd, раз юзер пишет ее, у него есть на то причины), или же этот абзац тоже подразумевает установку текста командной строки и выполнение для смены папки (маловероятно, что ты имел в виду это, но вдруг)?

#25:  Author: HankHank PostPosted: Tue Apr 20, 2010 09:16
    —
Тока появился на работе. Ничего ещё не успел, а в форуме – такая радость – детальный ответ. Very Happy Отвечу тогда сразу, а позже уже - эксперименты.
MVV wrote:

Ты выделил в стеке место для буфера и вписал в него путь. Далее, ты вызываешь фоновую функцию и передаешь ей адрес этого буфера, и не дожидаясь ее завершения выходишь из функции, в которой буфер был выделен, то есть, уничтожаешь его!

Было подозрение, что может повлиять. Поскольку программирую эпизодически, и нет качественной документации под рукой, лезу в Тырнет. Где-то нашёл, что функция передачи сообщений с указанным параметром WM_COPYDATA работает синхронно, т.е. ждёт, когда дойдут параметры в hMainWnd. И перенёс бездумно увиденное. Не учёл процесса.

MVV wrote:

Еще один момент - плагин у юзера необязательно будет называться "net", имя можно дать любое в настройке FS-плагинов.

Это точно. Но пока что надо получить работоспособную программулину. Причешу позже.

MVV wrote:

Кстати, заметил, что у меня может теряться память, если будет ошибка создания фонового потока. Модернизировал:…

Беру на вооружение.

MVV wrote:

На оффтоп отвечать не буду, раз модераторы против. Хотя, могу в личку.

Не будем хулиганить. Напиши в личку. Найдётся ещё вопрос-другой. Может, и я на что сгожусь.

MVV wrote:

HankHank wrote:
При нахождении “в среде плагина” попытка ввести “cd \\< IP или имя>” не приводит к успеху – надо слегка подриххтовать логику. Ты, впрочем, об этом вскользь уже говорил.

…Ты вводишь команду для перехода в сетевую папку, находясь в папке плагина, и оно не работает (в ТК команда cd не работает в папках FS-плагинов; ты должен вручную реализовать обработку команды cd и изменить текущую папку - например, вызвав ChangeCurrentDir, как делает моя VirtualPanel), или ты пытаешься обойти хук с помощью команды cd (я говорил как раз об этом - не нужно блокировать команду cd, раз юзер пишет ее, у него есть на то причины), или же этот абзац тоже подразумевает установку текста командной строки и выполнение для смены папки (маловероятно, что ты имел в виду это, но вдруг)?

Пользователю невдомёк, что командная строка работает по-разному в плагине и без него. Поэтому не хотелось бы забивать ему мозги ещё и такими деталями. И надо бы это как-то реализовать... Да, и в принципе, возможна ситуёвина, когда в обеих панелях уже плагин, а пользователь ещё и в командной строке набирает типа cd \\<хост>.

#26:  Author: MVVLocation: Ростов-Дон PostPosted: Tue Apr 20, 2010 10:45
    —
HankHank wrote:
Пользователю невдомёк, что командная строка работает по-разному в плагине и без него. Поэтому не хотелось бы забивать ему мозги ещё и такими деталями. И надо бы это как-то реализовать... Да, и в принципе, возможна ситуёвина, когда в обеих панелях уже плагин, а пользователь ещё и в командной строке набирает типа cd \\<хост>.

Вот для этого и нужно обрабатывать команду cd, выдирать ее параметр и устанавливать как путь - делается элементарно. Я лично проверяю, есть ли кавычка в начале параметра - если есть, считаю путем то, что в кавычках, если нету - считаю путем весь параметр команды cd (за исключением пробелов, идущих в самом конце строки):
Code:
cd "путь\путь" не путь 
cd путь\п у т ь\путь путь     


В функции FsExecuteFileW смотришь, если строка Verb начинается с "quote cd " (лучше сравнивать без учета регистра) - и действуешь, анализируя параметр команды (то есть, строку Verb+9).

#27:  Author: AvadaLocation: Россия, Саратов PostPosted: Tue Apr 20, 2010 11:35
    —
HankHank
MVV
Мне кажется, тему лучше перенести в подфорум "Написание плагинов", поскольку обсуждаемые вопросы — достаточно специфические. Нет возражений?

#28:  Author: HankHank PostPosted: Tue Apr 20, 2010 11:41
    —
Avada:
Переносите, конечно.

MVV:
В личке посмотри.

 !  Avada:
Тема перенесена.

#29:  Author: MVVLocation: Ростов-Дон PostPosted: Tue Apr 20, 2010 15:03
    —
Avada wrote:
Мне кажется, тему лучше перенести в подфорум "Написание плагинов", поскольку обсуждаемые вопросы — достаточно специфические. Нет возражений?

У меня у самого такая мысль была - полотна исходников явно не для общего подфорума.

HankHank wrote:
В личке посмотри.

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

HankHank wrote:
Покуролесил с вчерашним кодом в свете твоего сообщения о динамической памяти:
Code:

DWORD __stdcall BackgroundSendData(void* Data)
{
   int ii=SendMessage(hMainWnd, WM_COPYDATA, 0, (LPARAM) Data);
   return 0;
}

static COPYDATASTRUCT cds;
static char buffer[]="cd \\\\\\net";

bool ChangeCurrentDir()
{
   cds.dwData='DC';
   cds.lpData=&buffer;
   cds.cbData=sizeof(buffer);

   HANDLE thread=CreateThread(0, 0, &BackgroundSendData, &cds, 0, 0);
   if (!thread) return 0;

   CloseHandle(thread);
   return 1;
}

Передаваемая процессу память никуда теперь не исчезает. Но код проще. (Пробовал static char buffer[]="cd \\\\\\net" и static char buffer[]="\\\\\\net".)
Но что-то ничего не выходит…

Конечно, код проще. Тебе ж не нужно каждый раз менять содержимое буфера, поэтому и статический буфер подойдет.
А почему не работает, ща объясню. Видимо, ты плохо разобрался с форматом буфера для WM_COPYDATA, который ожидает ТК. Вот он:
Code:
<first_path>\r<second_path>\0<flags>

Флаги: 'T' - в новой вкладке, 'S' - менять пути активной и неактивной панелей вместо левой и правой.

Таким образом, правильный буфер:
Code:
static char cdnet[]="\\\\\\net\r\0S";

(то есть, изменить путь на \\\net в активной панели)

Но размер такого буфера уже функцией strlen не определишь - внутри есть нулевой символ. Поэтому либо TSIZE(cdnet), либо ручками циферку. И циферка обязательно должна включать нулевой байт в конце буфера - иначе ТК может хрен знает куда зайти в его поисках и набрать себе левых флагов из блока памяти за пределами буфера (я с таким уже сталкивался, обсуждение тут).

#30:  Author: HankHank PostPosted: Tue Apr 20, 2010 15:46
    —
MVV wrote:
Видимо, ты плохо разобрался с форматом буфера для WM_COPYDATA, который ожидает ТК. Вот он:
Code:
<first_path>\r<second_path>\0<flags>

Флаги: 'T' - в новой вкладке, 'S' - менять пути активной и неактивной панелей вместо левой и правой.

Так ясно. По началу строчка wsprintf показалась заумной. И я решил, что хватит с меня и первого параметра с путём, куда надо переключить активную панель. А откуда эта инфо ?

MVV wrote:
Таким образом, правильный буфер:
Code:
static char cdnet[]="\\\\\\net\r\0S";


Да, так работает. Буду ковать дальше.

Ещё заметил такую деталь. Может, интересно кому.
Вот здесь http://www.firststeps.ru/mfc/winapi/win/r.php?126 прочитал про WM_COPYDATA:
Quote:
Если принимающая программа обрабатывает это сообщение, она должна возвратить значение ИСТИНА (TRUE); в противном случае она должна возвратить - ЛОЖЬ (FALSE).

У меня же передача параметров срабатывает, происходит переход куда требуется, но SendMessage возвращает при этом 0.

#31:  Author: MVVLocation: Ростов-Дон PostPosted: Tue Apr 20, 2010 16:02
    —
HankHank wrote:
MVV wrote:
Видимо, ты плохо разобрался с форматом буфера для WM_COPYDATA, который ожидает ТК. Вот он:
Code:
<first_path>\r<second_path>\0<flags>

Флаги: 'T' - в новой вкладке, 'S' - менять пути активной и неактивной панелей вместо левой и правой.

Так ясно. По началу строчка wsprintf показалась заумной. И я решил, что хватит с меня и первого параметра с путём, куда надо переключить активную панель. А откуда эта инфо ?

Ну, официально Гислер вроде это не документировал, в history.txt упоминается только про само сообщение без описания формата. Но вообще на TotalcmdWiki есть пример функции, отправляющей WM_COPYDATA.

HankHank wrote:
MVV wrote:
Таким образом, правильный буфер:
Code:
static char cdnet[]="\\\\\\net\r\0S";


Да, так работает. Буду ковать дальше.

Это главное. Значит, я не ошибся, когда составлял эту строчку. Very Happy

HankHank wrote:
Ещё заметил такую деталь. Может, интересно кому.
Вот здесь http://www.firststeps.ru/mfc/winapi/win/r.php?126 прочитал про WM_COPYDATA:
Quote:
Если принимающая программа обрабатывает это сообщение, она должна возвратить значение ИСТИНА (TRUE); в противном случае она должна возвратить - ЛОЖЬ (FALSE).

У меня же передача параметров срабатывает, происходит переход куда требуется, но SendMessage возвращает при этом 0.

Я обычно читаю MSDN. Но суть не в том. Не обращай внимание на то, что должно быть. Тем более, имея дело с VCL, на которой построены окошки в дельфийских программах - там черт ногу сломит. Кроме того, ничто не мешает ТК обработать сообщение, но вернуть 0. И в нашем случае цель отправки сообщения - не возвращаемое значение, а действие. Smile

#32:  Author: HankHank PostPosted: Tue Apr 20, 2010 21:43
    —
Хочется задействовать командную строку в плагине. Минимальными трудозатратами. Можно попытаться отдать строку Коммандеру, после чего умыть руки. А он уж её пускай обрабатывает.
На уровне идеи, без реализации, на примере клавиатурного хука выглядит как-то так:

Code:


DWORD __stdcall ExecEmulate(void)
{
   // focus to command line
   SendMessage(hMainWnd, WM_USER + 51, 4003, 0);
   // ENTER-pressing
   keybd_event(VK_RETURN, 0, KEYEVENTF_EXTENDEDKEY, 0);
   return 0;
}

bool ExecCommandLine()
{
   HANDLE thread=CreateThread(0, 0, ExecEmulate, 0, 0, 0);
   if (!thread) return 0;
   CloseHandle(thread);
   return 1;
}

LRESULT CALLBACK CallMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
   if (wParam==WM_LBUTTONDBLCLK)
   {
      HWND mylb=GetActivePanel();
      POINT pt;
      GetCursorPos(&pt);
      ScreenToClient(mylb, &pt);
      int index=SendMessage(mylb, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y)); // get item index under cursor
      if (!index&&IsForbiddenLevelUp())
      { // it is ".." item and we should refuse 'level up'
         HWND cmdpanel, edit;
         if ((cmdpanel=FindWindowEx(hMainWnd, cmdpanel, "TMyPanel", "")))
            if ((edit=FindWindowEx(cmdpanel, edit, "TMyComboBox", "")))
               if ((FindWindowEx(edit, 0, "TMyComboBox", "")))
               {
                  char buf[1024];
                  int k=GetWindowText(edit, buf, TSIZE(buf));
                  
pseudo code: if buf not emty then
                     ExecCommandLine();

                  
                  return 1; // kill doubleclick event
               }


         DoMyAction();
         return 1; // kill doubleclick event
      }
   }
   return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}

Принял обтекаемую форму. Very Happy Вижу, что топорно.

#33:  Author: MVVLocation: Ростов-Дон PostPosted: Tue Apr 20, 2010 22:23
    —
Я ваще не пойму, какое отношение имеет мышиный хук к командной строке - вход в папку с помощью мыши в ТК никогда не затрагивал содержимого командной строки.
И потом, не пойму, зачем тебе командная строка в пределах твоего плагина - какие там могут быть команды? Пускай юзер перейдет в нормальную папку - благо, команду cd ты ему обеспечишь - а там уже выполняет любые команды.
Наконец, панель состояния - далеко не единственная панель в окне ТК, поэтому просто поиском окна с заданным классом искать ее не советую. В моем примере панель пути искалась до тех пор, пока найденная панель не содержала знак больше в конце строки - иначе это могла быть, скажем, панель с информацией о свободном месте на диске (в ТК 7.04a и ТК 7.50a некоторые классы окон называются по-разному).

#34:  Author: HankHank PostPosted: Wed Apr 21, 2010 09:09
    —
MVV wrote:
Я ваще не пойму, какое отношение имеет мышиный хук к командной строке - вход в папку с помощью мыши в ТК никогда не затрагивал содержимого командной строки.

Речь всего лишь о подходящем месте. Идея состоит в том, чтобы именно из хука отправить содержимое командной строки, если оно, конечно, там есть. А хуки должны быть использованы оба, и клавиатурный в том числе.

MVV wrote:
зачем тебе командная строка в пределах твоего плагина - какие там могут быть команды?

Да мне лично по барабану командная строка в плагине. А пользователю всё едино, если он зашёл в Коммандер – что плагин, что “штатные панели”. Т.е. для того, чтобы не нарушать его “целостности представления” об интерфейсе. Юзеру же в голову может прийти сделать что-нибудь и другое, например: “copy a.txt b.txt” в любом месте TC.

MVV wrote:
панель состояния - далеко не единственная панель в окне ТК, поэтому просто поиском окна с заданным классом искать ее не советую.

Здесь мои представления слабы.
Каким разумным способом можно поискать командную строку и извлечь её содержимое ?

ЗЫ
Что касается версий, то меня вполне устраивают TC не ниже 7.50.

#35:  Author: HankHank PostPosted: Wed Apr 21, 2010 11:12
    —
Всех деталей не упомнишь. Поэтому некоторые уточнения.
Посмотрел попристальнее на командную строку в обычных режимах Коммандера и в плагине.
В обычном режиме (файловые панели) строка выполняется Коммандером только при переводе в неё фокуса ввода после двойного щелчка мышью или нажатия Enter. (Этот момент, кстати, некоторые используют для кратковременного хранения коротких информационных строчек и совсем по разному поводу. Работают в др. приложении или TC, а строчки временно хранят в ком. строке. Изврат, но реально используется).
Пока у меня в плагине осуществляется вылет в сетевое окружение коммандера (где все плагины) после двойного клика или нажатия Enter.

#36:  Author: MVVLocation: Ростов-Дон PostPosted: Wed Apr 21, 2010 12:07
    —
Quote:
А пользователю всё едино, если он зашёл в Коммандер – что плагин, что “штатные панели”.

Между прочим, какую папку ты будешь делать текущей при выполнении команды из папки твоего плагина? У тебя она там попросту неопределена. Да и команда copy - это внутренняя команда командного интерпретатора Windows, она без него вообще не работает, а ему тоже нужна рабочая папка.

Quote:
Каким разумным способом можно поискать командную строку и извлечь её содержимое ?

Юзай мой способ поиска панели с текущим путем (путь тебе все равно пригодится) - рядом (с тем же предком) будет окно командной строки. Wink

Quote:
Посмотрел попристальнее на командную строку в обычных режимах Коммандера и в плагине.

Да, я об этом и говорил. Я сам иногда перехожу между папками мышью, чтобы не стирать набранную командную строку - и я не ожидаю, что она будет выполнена в этот момент.

Quote:
Пока у меня в плагине осуществляется вылет в сетевое окружение коммандера (где все плагины) после двойного клика или нажатия Enter.

То есть, ничего не работает? А как же хуки, которые блокируют команду и устанавливают нужный путь?

#37:  Author: HankHank PostPosted: Wed Apr 21, 2010 22:56
    —
Извини, мысли с утра формулировались с трудом - текучка. На программирование время по остаточному принципу.
Поясняю подробнее.
MVV wrote:
Quote:
А пользователю всё едино, если он зашёл в Коммандер - что плагин, что "штатные панели".

Между прочим, какую папку ты будешь делать текущей при выполнении команды из папки твоего плагина? У тебя она там попросту неопределена. Да и команда copy - это внутренняя команда командного интерпретатора Windows, она без него вообще не работает, а ему тоже нужна рабочая папка.

Команда copy - только для примера. И пример, канеш, неполный. Если к файлам добавить пути и написать так:
Code:

copy c:\temp\a.txt d:\temp2\b.txt
, то должно стать понятным, что я имел в виду - какую-то команду для командного процессора. Или ту же команду перехода на хост типа
Code:

cd \\192.168.1.2
и т.п.
В общем, что в голову взбредёт. Т.е. пользователю удобно в принципе использовать командную строку, как он привык. Он её непременно вобъёт и в моей самописной мульке. У нас юзеры привыкли к Коммандеру. И особенно не заморачиваются раздумьями "что да почему". TC - как-бы часть ОС. Very Happy

MVV wrote:
Юзай мой способ поиска панели с текущим путем (путь тебе все равно пригодится) - рядом (с тем же предком) будет окно командной строки. Wink

Пасиб.

MVV wrote:
Quote:
Посмотрел попристальнее на командную строку в обычных режимах Коммандера и в плагине.

Да, я об этом и говорил. Я сам иногда перехожу между папками мышью, чтобы не стирать набранную командную строку - и я не ожидаю, что она будет выполнена в этот момент.

Вот и ты тоже используешь как временный "карман".

MVV wrote:
Quote:
Пока у меня в плагине осуществляется вылет в сетевое окружение коммандера (где все плагины) после двойного клика или нажатия Enter.

То есть, ничего не работает? А как же хуки, которые блокируют команду и устанавливают нужный путь?

Всё работает на ура. Ходьба вверх-вниз через итем [..] происходит лучше не придумаешь. На порядок лучше, чем в AHK. А вот вариант, когда дополнительно что-то введено в командную строку TC + в одной из панелей сетевое окружение моего плагина "на верхнем уровне" + в командной строке делаю двойной клик мышью или нажимаю Enter, - вот тогда происходит вылет на уровень выше, т.е в сетевое окружение коммандера (где список плагинов и прочее). А должна по идее выполниться командная строка.

Захотелось из хорошего сделать ещё лучше - задействовать командную строку и в этом случае. Так сказать, поставить логическую точку. Так понятней ?

#38:  Author: MVVLocation: Ростов-Дон PostPosted: Thu Apr 22, 2010 00:17
    —
Quote:
Всё работает на ура. Ходьба вверх-вниз через итем [..] происходит лучше не придумаешь. На порядок лучше, чем в AHK.

Ну дык) чистый ассемблер куда лучше всяких байт-кодов.

Quote:
А вот вариант, когда дополнительно что-то введено в командную строку TC + в одной из панелей сетевое окружение моего плагина "на верхнем уровне" + в командной строке делаю двойной клик мышью или нажимаю Enter, - вот тогда происходит вылет на уровень выше, т.е в сетевое окружение коммандера (где список плагинов и прочее). А должна по идее выполниться командная строка.

Чего-то я не понимаю. Если в командной строке делать даблклик или жать Enter, ТК чисто выполняет командную строку, при этом папка не меняется (если, конечно, команда не cd). И этот клик по идее игнорируется хуками, так как при этом активное окно - не файловая панель. И поведение это изменению не поддается, да и нет в том необходимости. Или ты хочешь выполнять эту командную строку?

Под сетевым окружением твоего плагина "на верхнем уровне" ты понимаешь папку своего плагина?

#39:  Author: HankHank PostPosted: Thu Apr 22, 2010 10:32
    —
MVV wrote:
Под сетевым окружением твоего плагина "на верхнем уровне" ты
понимаешь папку своего плагина?

Согласен, коряво и длинно выазился. Недостаток общения по обсуждаемой проблематике. Very Happy Но ты понял верно: да, именно папка моего плагина и есть место преткновения.

MVV wrote:
Если в командной строке делать даблклик или жать Enter, ТК чисто выполняет командную строку, при этом папка не меняется (если, конечно, команда не cd).

Совершенно справедливо для типовых файловых панелей.

MVV wrote:
И этот клик по идее игнорируется хуками, так как при этом активное окно - не файловая панель.

Активна не файловая панель, в которой в этот момент папка моего плагина. Активной оказывается командная строка. На ней фокус ввода.

MVV wrote:
И поведение это изменению не поддается, да и нет в том необходимости.

Получается нелогичное с точки зрения неискушённого юзера поведение TC.
Это поведение одинаково для любого элемента списка папки моего плагина, необязательно для начального элемента списка [..]. При даблклике или нажатии Enter (в активном окне) командной строки происходит “вылет” на уровень вверх с установкой курсора на начало списка плагинов. При этом командная строка ”проглатывается” Коммандером, но команду он при этом не выполняет...

------------------------------
Блииин... Полезно бывает копаться в деталях. Только сейчас допёрло, что у меня в этот момент слева от командной строки изображено-то: \\\net> Exclamation
Ну, лопухнулся. Я этот момент не отслеживаю как надо. А как надо Question

MVV wrote:
Или ты хочешь выполнять эту командную строку?

Именно так. Мне представляется логичным выполнить командную строку в папке моего плагина, если у юзера есть в том необходимость.

#40:  Author: HankHank PostPosted: Thu Apr 22, 2010 11:03
    —
Решение напрашивается такое.
В функции InitializeHooks(), помимо окна класса TMyPanel, содержащего магический значок “>” в конце пути, надо найти хэндл на класс Edit - editpanel. Интересно, он один с таким именем в оконном списке ?
А в хуках уже смотреть, не пустая ли командная строка с помощью GetWindowText(editpanel, buf, TSIZE(buf)) ?
Если не пустая, выполнить функцию ExecCommandLine() из моей пурги в начале странички.

#41:  Author: MVVLocation: Ростов-Дон PostPosted: Thu Apr 22, 2010 13:03
    —
Уточню еще раз.

Если при нажатии клавиши Enter командная строка не пуста, то нажатие клавиши приводит к выполнению команды без смены текущей папки.

Если при нажатии клавиши Enter командная строка пуста, или же выполняется даблклик мышью по элементу файловой панели, то происходит изменение текущей папки без выполнения какой-либо команды и очистки командной строки.

Эти аспекты должны иметь место быть при работе с любыми файловыми панелями, будь то панели содержимого папки на диске, сетевой папки или папки плагина файловой системы. И их искажение я не считаю допустимым и в какой бы то ни было мере разумным.

Все что от тебя требуется - это при особом желании выполнить командную строку, которую ТК передаст тебе, вызывав функцию FsExecuteFile в момент нажатия юзером клавиши Enter или даблклике мышью по непустой командной строке. Извлекать текст командной строки при этом тебе абсолютно не нужно. Замечу, что в этом месте может играть роль то, что плагин не поддерживает Юникод, так как командная строка может содержать юникод-символы не из системной кодовой страницы. Также при выполнении команды не забывай, что текущая рабочая папка не определена.

Если тебе все-таки неймется, дескриптор командной строки ты можешь получить, если возьмешь GetParent() от дескриптора панели с текстом текущего пути, и в найденном окне найдешь TMyComboBox, в котором потом найдешь Edit (гарантированно тот самый, который нужен). Или же сразу встроишься в цикл поиска панели пути, где дескриптор родительского окна есть:
Code:
   while (1) {
      if (!(cmdpanel=FindWindowEx(hMainWnd, cmdpanel, "TMyPanel", L""))) break;
      if ((cmdlbox=FindWindowEx(cmdpanel, 0, "TMyComboBox", L"")) || (cmdlbox=FindWindowEx(cmdpanel, 0, "TComboBox", L""))) {
         HWND pathpanel=FindWindowEx(cmdpanel, 0, "TMyPanel", 0);
         int k=GetWindowText(pathpanel, buf, TSIZE(buf));
         if (k&&buf[k-1]=='>') {
            stpath=pathpanel;
            cmdline=FindWindowEx(cmdlbox, 0, "Edit", 0);
            break;
         }
      }
   }

(переменная cmdlbox - локальная, будет содержать дескриптор комбобокса с командной строкой, который в ТК 7.04a и 7.50a имеет разные классы - здесь ищутся оба; переменная cmdline - глобальная, получит дескриптор окна командной строки)

#42:  Author: HankHank PostPosted: Thu Apr 22, 2010 14:05
    —
MVV wrote:
...при особом желании выполнить командную строку, которую ТК передаст тебе, вызывав функцию FsExecuteFile в момент нажатия юзером клавиши Enter или даблклике мышью по непустой командной строке. Извлекать текст командной строки при этом тебе абсолютно не нужно.

Вот этот момент я совершенно упустил из виду. Плохо изучал API. Собственно, это и есть исчерпывающее решение.

И за это также респект:
MVV wrote:
Замечу, что в этом месте может играть роль то, что плагин не поддерживает Юникод, так как командная строка может содержать юникод-символы не из системной кодовой страницы. Также при выполнении команды не забывай, что текущая рабочая папка не определена.


Пазл собрался. Very Happy
Всем, кто помогал найти решение, - сердечная благодарность.



Total Commander -> Написание плагинов для Total Commander


output generated using printer-friendly topic mod. All times are GMT + 4 Hours

Page 1 of 1

Powered by phpBB © 2001, 2005 phpBB Group