Путь противоположной панели

Только для тех, кто пишет плагины под Total Commander. Обмен опытом, решение проблем.

Модераторы: d-view, Моторокер, Avada, CaptainFlint, Nik

Ответить
Аватара пользователя
Maximus
Сообщения: 927
Зарегистрирован: Чт апр 07, 2005 10:51
Откуда: Украина, Кировоградская обл., г. Знаменка
Контактная информация:

Путь противоположной панели

Сообщение Maximus »

Знает ли кто способы получения пути в противоположной панели TC из WFX-плагина?
Естественно напрашивается вывод использовать EnumChildWindows с поиском контрола по имени TPathPanel, текст которого не содержит в начале три черты \\\.
Но может есть способ поровнее?
Последний раз редактировалось Maximus Вт июл 03, 2012 01:17, всего редактировалось 1 раз.
Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

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

25.11.11 Release Total Commander 8.0 public beta 10 (32/64)
25.11.11 Added: Send WM_COPYDATA with dwData='G'+256*'W': Same as with 'G'+256*'A', but data is returned as UTF-16 Unicode. dwData of return is 'R'+256*'W' (32/64)
25.11.11 Added: Send WM_COPYDATA with dwData='G'+256*'A' and lpData pointing to command to get back WM_COPYDATA with various info. Supported commands A: Active side (returns L or R), or two byte command: first byte: L=left, R=right, S=source, T=target. Second byte: P=current path, C=list count, I=caret index, N=name of file under caret. dwData of return is 'R'+256*'A' (32/64)
Как вариант. Естественно, не работает в более старых версиях.

А вообще, во время вызова какой конкретно функции это нужно? В силу пассивности WFX-плагинов не вижу необходимости узнавать путь вне вызовов тоталом функций плагина.
Аватара пользователя
Maximus
Сообщения: 927
Зарегистрирован: Чт апр 07, 2005 10:51
Откуда: Украина, Кировоградская обл., г. Знаменка
Контактная информация:

Сообщение Maximus »

MVV
Я так и знал, что ты мне поможешь :)
Похоже на то, что нужно. Даже нашёл твой пример на офсайте.

А что за выражение такое?
dwData='G'+256*'A'
Зачем было писать так интересно?
В твоём примере всё просто
cds.dwData='AG';
А вообще, во время вызова какой конкретно функции это нужно? В силу пассивности WFX-плагинов не вижу необходимости узнавать путь вне вызовов тоталом функций плагина.
Телефонная книга. Хочу завести псевдофайл при запуске которого будет выполняться экспорт всех контактов в один файл. Будет открываться диалог сохранения, куда и буду подставлять путь противоположной панели, если он окажется корректным.

Собственно я уже научился делать это описанным мною выше способом, а теперь хочу сделать то же, но правильно :)
Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

Maximus писал(а):А что за выражение такое?
dwData='G'+256*'A'
Зачем было писать так интересно?
В твоём примере всё просто
cds.dwData='AG';
Ну, то писал Гислер, можно было записать как 'G'+('A'<<8). А я знаю, что можно писать многосимвольные константы, заключая их в одиночные кавычки и инвертируя порядок, потому пишу просто 'AG' :) Кстати, некоторые компиляторы (гнутый, например) выдают ахтунг на такую запись, хотя и компилируют правильно.
Цель достигается и так и так - получить в данном примере в 4 байтах памяти этой переменной строку "GA" - понять бы, что означает буква 'G' ('A' означает ANSI). Для смены каталога надо получить там строку "CD" (для чего я использую запись 'DC'). У себя для Virtual Panel я использую 'PV' (строка "VP"), а для юникода - 'P\0V' (строка L"VP" без терминатора).

Ну да, в принципе, в FsExecuteFile путь неактивной панели никак не получить прямым способом. А может для экспорта лучше использовать копирование какого-нибудь псевдофайла в неактивную панель? По-моему, вполне логично для экспорта использовать копирование. Тогда юзер сам выберет путь прямо в тотальном диалоге, и тотал укажет его тебе, вызвав функцию FsGetFile.
Последний раз редактировалось MVV Вт июл 03, 2012 11:15, всего редактировалось 2 раза.
Аватара пользователя
Maximus
Сообщения: 927
Зарегистрирован: Чт апр 07, 2005 10:51
Откуда: Украина, Кировоградская обл., г. Знаменка
Контактная информация:

Сообщение Maximus »

MVV писал(а):А может для экспорта лучше использовать копирование какого-нибудь псевдофайла в неактивную панель? По-моему, вполне логично для экспорта использовать копирование. Тогда юзер сам выберет путь прямо в тотальном диалоге, и тотал укажет его тебе, вызвав функцию FsGetFile.
Будет и то и другое. Просто для пользователя понятнее будет запуск псевдофайла с именем "Экспорт всего на свете", чем копирование файла contacts.vcf. Поэтому функционал будет продублирован - для запуска этого элемента и для его копирования.
Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

Ну в принципе да, можно и продублировать. Но окошки искать, конечно, занятие не из приятных. Особенно с учетом того, что в разных версиях иерархия слегка различается. Не говоря уже о 64-битной версии, где почти все дочерние окна имеют имя класса Window.
Аватара пользователя
Maximus
Сообщения: 927
Зарегистрирован: Чт апр 07, 2005 10:51
Откуда: Украина, Кировоградская обл., г. Знаменка
Контактная информация:

Сообщение Maximus »

MVV писал(а):Но окошки искать, конечно, занятие не из приятных. Особенно с учетом того, что в разных версиях иерархия слегка различается. Не говоря уже о 64-битной версии, где почти все дочерние окна имеют имя класса Window.
Вот потому и хотелось сделать всё не костылями, а как положено.
Аватара пользователя
Maximus
Сообщения: 927
Зарегистрирован: Чт апр 07, 2005 10:51
Откуда: Украина, Кировоградская обл., г. Знаменка
Контактная информация:

Сообщение Maximus »

MVV
Чтото не идет у меня WM_COPYDATA. TC ничего не отвечает. Не сталкивался ли ты с подобным во время отладки?

Добавлено спустя 1 час 22 минуты:

SendMessage возвращает false.
Пытаюсь послать сообщение в своё же приложение - результат тот же.

Добавлено спустя 28 минут:

Внезапно всё заработало. Причины неработы непонятны. Вероятно, что файервол-антивирус. Такое вообще возможно? Заработало через некоторое время после отключения. Но сейчас работает и при включенном.

А можно ли сообщение WM_COPYDATA каким-то образом обработать не в оконной процедуре, а в самой DLL?
Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

Пардон, что значит "не в оконной процедуре, а в самой DLL"? Если у тебя оконная процедура твоего окна в DLL, то можно и нужно.
Аватара пользователя
Maximus
Сообщения: 927
Зарегистрирован: Чт апр 07, 2005 10:51
Откуда: Украина, Кировоградская обл., г. Знаменка
Контактная информация:

Сообщение Maximus »

Я имел в виду, если DLL не создает никаких окон.
Аватара пользователя
MVV
Сообщения: 4815
Зарегистрирован: Чт окт 15, 2009 10:58
Откуда: Ростов-Дон

Сообщение MVV »

А тебе просто необходимо окно, чтобы получить ответ, иначе никак. Подцепляться к оконной процедуре тотала в данной ситуации - абсолютно некорректно.

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

//25.11.11 Added:
// Send WM_COPYDATA with dwData='G'+256*'W': Same as with 'G'+256*'A', but data is returned as UTF-16 Unicode. dwData of return is 'R'+256*'W' (32/64)

//25.11.11 Added:
// Send WM_COPYDATA with dwData='G'+256*'A' and lpData pointing to command to get back WM_COPYDATA with various info.
// Supported commands
// A: Active side (returns L or R), or two byte command: first byte: L=left, R=right, S=source, T=target.
// Second byte: P=current path, C=list count, I=caret index, N=name of file under caret. dwData of return is 'R'+256*'A' (32/64)

struct SendCopyData_t {
	const COPYDATASTRUCT* cds_in;
	COPYDATASTRUCT* cds_out;
};

LRESULT __stdcall SendCopyDataProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	if (uMsg==WM_CREATE) {
		CREATESTRUCT& cs=*(CREATESTRUCT*)lParam;
		SendCopyData_t& scd=*(SendCopyData_t*)cs.lpCreateParams;
		HWND htcwnd=FindWindow(L"TTOTAL_CMD", 0);
		SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)&scd);
		scd.cds_out->dwData=0;
		int r=SendMessage(htcwnd, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)scd.cds_in);
		PostQuitMessage(r ? 0 : 1);
	}
	else if (uMsg==WM_COPYDATA) {
		SendCopyData_t& scd=*(SendCopyData_t*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
		COPYDATASTRUCT& cds=*(COPYDATASTRUCT*)lParam;
		scd.cds_out->dwData=cds.dwData;
		scd.cds_out->cbData=cds.cbData;
		memcpy(scd.cds_out->lpData, cds.lpData, cds.cbData);
		return 1;
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}


bool SendCopyData(const COPYDATASTRUCT* cds_in, COPYDATASTRUCT* cds_out) {
	SendCopyData_t scd={cds_in, cds_out};

	const WNDCLASS wc={0, SendCopyDataProc, 0, 0, GetModuleHandle(0), 0, 0, 0, 0, L"SendCopyDataWnd"};
	HWND hWnd=CreateWindow((LPWSTR)RegisterClass(&wc), wc.lpszClassName, 0, 0, 0, 0, 0, 0, 0, wc.hInstance, &scd);

	if (!hWnd) return 0;

	while (1) {
		MSG msg;
		if (!~GetMessage(&msg, hWnd, 0, 0)) return 0;
		if (msg.message==WM_QUIT) return msg.wParam!=0;

		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}
Так можно создать временное окно и послать нужное сообщение. Структура cds_in заполняется как обычно, а структура cds_out должна содержать адрес и размер буфера, куда будет возвращена строка от тотала, и размер данных при возвращении будет установлен в тот, что вернёт тотал.
Аватара пользователя
Maximus
Сообщения: 927
Зарегистрирован: Чт апр 07, 2005 10:51
Откуда: Украина, Кировоградская обл., г. Знаменка
Контактная информация:

Сообщение Maximus »

MVV
Спасибо. Как то про динамическое создание окна не подумалось.
Пригодится. А то вскоре за AppLoader браться, а там получение текущего пути на костылях :)
Аватара пользователя
Maximus
Сообщения: 927
Зарегистрирован: Чт апр 07, 2005 10:51
Откуда: Украина, Кировоградская обл., г. Знаменка
Контактная информация:

Сообщение Maximus »

Взялся за AppLoader...
Опробовал приведённый выше пример.

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

      if (!~GetMessage(&msg, hWnd, 0, 0)) return 0;
1. ~ - опечатка?
2. Пока не поставил NULL вместо hWnd висло при втором входе в GetMessage. Чем объяснить?
Ответить