Страница 2 из 3

Добавлено: Вс апр 18, 2010 12:50
VadiMGP
MVV писал(а):В функции IsForbiddenLevelUp я беру текст из панели в строке состояния, текст в которой есть независимо от режима панели.
Тогда может быть другое ложное срабатывание - при выходе из виртуальной папки. Если, к примеру, ты в Control Panel, то текст панели будет "\\Control Panel\*.*".

Добавлено: Вс апр 18, 2010 14:34
MVV
VadiMGP писал(а):
MVV писал(а):В функции IsForbiddenLevelUp я беру текст из панели в строке состояния, текст в которой есть независимо от режима панели.
Тогда может быть другое ложное срабатывание - при выходе из виртуальной папки. Если, к примеру, ты в Control Panel, то текст панели будет "\\Control Panel\*.*".
Вообще-то, конечно, "\\Панель управления>", но это детали. На этот счет я рекомендовал запоминать имя папки верхнего уровня и действовать только в том случае, если оно не изменилось - моя задача была раскрыть общую идею того, как работать с хуками.

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

Добавлено: Вс апр 18, 2010 21:48
MVV
Тут проблема действительна для любой виртуальной папки вообще, так что панель управления - лишь пример.

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

Добавлено: Пн апр 19, 2010 10:02
HankHank
Привет, MVV.

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

Код: Выделить всё

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

Код: Выделить всё

bool IsForbiddenLevelUp()
{
	char buf[1024];
	GetWindowText(stpath, buf, TSIZE(buf));
	if (!((buf[0]=='\\' && buf[1]=='\\') || buf[2]=='\\')) 
…
и… всё заработало почти с пол-оборота. Отдаю должное профессиональной прозрачности написанного кода. И всё это – при вполне удовлетворительной скорости.

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

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

Код: Выделить всё

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-библиотеки. Поэтому был слегка озадачен, когда увидел, что вызов

Код: Выделить всё

BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
происходит несколько раз (!) с параметрами ul_reason_for_call 1 и 2 – запуск самого процесса и первого его TREAD'а. Меня, собственно интересовал момент с условием

Код: Выделить всё

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

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

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

С уважением.

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

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


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

Код: Выделить всё

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 уже не тянет).


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

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

Код: Выделить всё

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 ? Так ли нельзя без него обойтись ?

Добавлено: Пн апр 19, 2010 16:33
Avada
HankHank писал(а):И ещё немного оффтопа.
А вот этого не надо. Правила форума существуют для того, чтобы их соблюдали.
Ответ на первый вопрос — например, здесь. Или здесь. Второй вопрос имеет смысл прояснять в подфоруме по разработке плагинов, к "Общим вопросам" он никак не относится.

Добавлено: Пн апр 19, 2010 18:04
MVV
HankHank писал(а):Попробовал приладить код с вызовом фонового процесса, получилось так: Компиллятор не взбрыкнул. Нужный процесс рождается. Код возврата thread ненулевой. Но эффекта - нет. Так и стоим на месте - на [..]. Подробнее пока не глядел.
Может, свежим взглядом косяк виден сразу ?
Ну молодец! Так и до вылета ТК в трубу недалеко. :D

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

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

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


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

Код: Выделить всё

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 (вроде так, проверить нет времени; функция фонового потока общая):

Код: Выделить всё

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 писал(а):При нахождении “в среде плагина” попытка ввести “cd \\< IP или имя>” не приводит к успеху – надо слегка подриххтовать логику. Ты, впрочем, об этом вскользь уже говорил.
Заметил этот абзац - и возник вопрос. Ты вводишь команду для перехода в сетевую папку, находясь в папке плагина, и оно не работает (в ТК команда cd не работает в папках FS-плагинов; ты должен вручную реализовать обработку команды cd и изменить текущую папку - например, вызвав ChangeCurrentDir, как делает моя VirtualPanel), или ты пытаешься обойти хук с помощью команды cd (я говорил как раз об этом - не нужно блокировать команду cd, раз юзер пишет ее, у него есть на то причины), или же этот абзац тоже подразумевает установку текста командной строки и выполнение для смены папки (маловероятно, что ты имел в виду это, но вдруг)?

Добавлено: Вт апр 20, 2010 09:16
HankHank
Тока появился на работе. Ничего ещё не успел, а в форуме – такая радость – детальный ответ. :D Отвечу тогда сразу, а позже уже - эксперименты.
MVV писал(а): Ты выделил в стеке место для буфера и вписал в него путь. Далее, ты вызываешь фоновую функцию и передаешь ей адрес этого буфера, и не дожидаясь ее завершения выходишь из функции, в которой буфер был выделен, то есть, уничтожаешь его!
Было подозрение, что может повлиять. Поскольку программирую эпизодически, и нет качественной документации под рукой, лезу в Тырнет. Где-то нашёл, что функция передачи сообщений с указанным параметром WM_COPYDATA работает синхронно, т.е. ждёт, когда дойдут параметры в hMainWnd. И перенёс бездумно увиденное. Не учёл процесса.
MVV писал(а): Еще один момент - плагин у юзера необязательно будет называться "net", имя можно дать любое в настройке FS-плагинов.
Это точно. Но пока что надо получить работоспособную программулину. Причешу позже.
MVV писал(а): Кстати, заметил, что у меня может теряться память, если будет ошибка создания фонового потока. Модернизировал:…
Беру на вооружение.
MVV писал(а): На оффтоп отвечать не буду, раз модераторы против. Хотя, могу в личку.
Не будем хулиганить. Напиши в личку. Найдётся ещё вопрос-другой. Может, и я на что сгожусь.
MVV писал(а):
HankHank писал(а):При нахождении “в среде плагина” попытка ввести “cd \\< IP или имя>” не приводит к успеху – надо слегка подриххтовать логику. Ты, впрочем, об этом вскользь уже говорил.
…Ты вводишь команду для перехода в сетевую папку, находясь в папке плагина, и оно не работает (в ТК команда cd не работает в папках FS-плагинов; ты должен вручную реализовать обработку команды cd и изменить текущую папку - например, вызвав ChangeCurrentDir, как делает моя VirtualPanel), или ты пытаешься обойти хук с помощью команды cd (я говорил как раз об этом - не нужно блокировать команду cd, раз юзер пишет ее, у него есть на то причины), или же этот абзац тоже подразумевает установку текста командной строки и выполнение для смены папки (маловероятно, что ты имел в виду это, но вдруг)?
Пользователю невдомёк, что командная строка работает по-разному в плагине и без него. Поэтому не хотелось бы забивать ему мозги ещё и такими деталями. И надо бы это как-то реализовать... Да, и в принципе, возможна ситуёвина, когда в обеих панелях уже плагин, а пользователь ещё и в командной строке набирает типа cd \\<хост>.

Добавлено: Вт апр 20, 2010 10:45
MVV
HankHank писал(а):Пользователю невдомёк, что командная строка работает по-разному в плагине и без него. Поэтому не хотелось бы забивать ему мозги ещё и такими деталями. И надо бы это как-то реализовать... Да, и в принципе, возможна ситуёвина, когда в обеих панелях уже плагин, а пользователь ещё и в командной строке набирает типа cd \\<хост>.
Вот для этого и нужно обрабатывать команду cd, выдирать ее параметр и устанавливать как путь - делается элементарно. Я лично проверяю, есть ли кавычка в начале параметра - если есть, считаю путем то, что в кавычках, если нету - считаю путем весь параметр команды cd (за исключением пробелов, идущих в самом конце строки):

Код: Выделить всё

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

Добавлено: Вт апр 20, 2010 11:35
Avada
HankHank
MVV
Мне кажется, тему лучше перенести в подфорум "Написание плагинов", поскольку обсуждаемые вопросы — достаточно специфические. Нет возражений?

Добавлено: Вт апр 20, 2010 11:41
HankHank
Avada:
Переносите, конечно.

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

[mod="Avada"]Тема перенесена.[/mod]

Добавлено: Вт апр 20, 2010 15:03
MVV
Avada писал(а):Мне кажется, тему лучше перенести в подфорум "Написание плагинов", поскольку обсуждаемые вопросы — достаточно специфические. Нет возражений?
У меня у самого такая мысль была - полотна исходников явно не для общего подфорума.
HankHank писал(а):В личке посмотри.
На вопросы по теме отвечу тут, может, кому-то пригодится. Надеюсь, не будешь сильно возражать.
HankHank писал(а):Покуролесил с вчерашним кодом в свете твоего сообщения о динамической памяти:

Код: Выделить всё

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, который ожидает ТК. Вот он:

Код: Выделить всё

<first_path>\r<second_path>\0<flags>
Флаги: 'T' - в новой вкладке, 'S' - менять пути активной и неактивной панелей вместо левой и правой.

Таким образом, правильный буфер:

Код: Выделить всё

static char cdnet[]="\\\\\\net\r\0S";
(то есть, изменить путь на \\\net в активной панели)

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

Добавлено: Вт апр 20, 2010 15:46
HankHank
MVV писал(а): Видимо, ты плохо разобрался с форматом буфера для WM_COPYDATA, который ожидает ТК. Вот он:

Код: Выделить всё

<first_path>\r<second_path>\0<flags>
Флаги: 'T' - в новой вкладке, 'S' - менять пути активной и неактивной панелей вместо левой и правой.
Так ясно. По началу строчка wsprintf показалась заумной. И я решил, что хватит с меня и первого параметра с путём, куда надо переключить активную панель. А откуда эта инфо ?
MVV писал(а): Таким образом, правильный буфер:

Код: Выделить всё

static char cdnet[]="\\\\\\net\r\0S";
Да, так работает. Буду ковать дальше.

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