Есть такая проблема: при двойном клике по файлу в "проводнике" он должен открыться в моей проге, я делал передачу пути к файлу через DDE. Все работает отлично, если прога запущена, в противном же случае - запускается моя прога, далее по хорошему должен по DDE передайться путь к файлу, так нет - выскакивает ошибка "Windows не удается найти файл..." и соответственно ничего не передается! Может быть кто-нибудь знает решение этой проблемы?
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
18-06-2006 13:36 | Комментарий к предыдущим ответам
Ну так и описали бы его в статье Обобщающий пример по работе с WinAPI
Он мне не нравится тем, что не даёт гарантию от повторного запуска программы, если запускать её прямо, а не через ассоциированные файлы. Поэтому, даже с использованием DDE, программе для предотвращения повторного запуска и передачи командной строки из второго экземпляра в первый пришлось бы делать всё то же самое, что и без DDE. А раз так - какой смысл приделывать к программе код, который в итоге не даёт никаких преимуществ?
>>> прописать в реестре
А разве FindWindow+SendMessage сложнее? Для ассоциации нужно создать в разделе HKEY_CLASSES_ROOT нужное расширение (прописать значение по умолчанию - описание файла), внутри прописать раздел DefaultIcon (значение по умолчанию - иконка, которую будет отображать Explorer, скорее всего - имя приложения, запятая, номер иконки в ресурсах) и Shell (значение по умолчанию - то, что будет отображаться в контекстном меню жирным и выполняться по умолчанию); в нем надо создать раздел, например Open (можно больше), внутри которого - раздел Command, в значение по умолчанию которого записать путь к своей программе в кавычках (если содержит пробел) и параметр %1 в кавычках (на случай, если он будет иметь пробел в имени)). Теперь при запуске программы стоит проверить через FindWindow или мьютексы, или MMF (Memory Mapped Files), что данное приложение еще не запущено, после чего проанализировать командную строку и если это необходимо, отправить сообщение WM_COPYDATA найденному окну (или по хендлу, который сохранен в MMF), или любое сообщение, передавая данные через мьютексы, атомы (»вопрос КС №41261«) или handle глобально выделенной области памяти. Подробнее можно почитать в »вопрос КС №34059«, »вопрос КС №34402«, готовую реализацию посмотреть в Использование WinAPI часть 3 или написать самому. В принципе я так привык и мне удобно.
Теперь давайте рассмотрим как делается через DDE. Помимо того, что мне придется создать раздел реестра как я описывал ранее, придется еще создать в разделе Command раздел ddeexec (в параметр по умолчанию пропиши макрос, который должен выполняться при попытке открытия файла, например open "%1", кавычки могут отсутствовать), в котором разместить разделы: application (в разделе по умолчанию - имя исполняемого файла, можно с путем, но без расширения .exe), и topic (там нужно указать имя компоненты TDDEServerConv в программе). Так? Продолжим. В программе потребуется закинуть компонент TDDEServerConv (название должно совпадать с тем, что прописано ранее в ассоциации, помните!) в OnExecuteMacro которого прописать нечто вроде:
procedure TDDEServer.pthConvExecuteMacro(Sender: TObject; Msg: TStrings);
begin
if Copy(Msg.Text,1,4)='open' then begin
открыть_файл(Copy(Msg.Text,7,Length(Msg.Text)-8);
end;
end;
Вот теперь вроде все. Кстати, если вспомнить, что DDE основан также на отправке сообщений, становится сомнительным хоть какой то выигрыш в эффективности или простоте использования этого подхода. Впрочем, программист должен знать оба метода. Как снайпер должен знать приемы рукопашного боя - на всякий случай.
04-06-2006 12:35 | Комментарий к предыдущим ответам
И все-таки лучше всего - технология ParamStr/WM_COPYDATA, потому что она прозрачнее DDE. KISS - Keep It Simple, Sydney.
Существует документированный способ сделать следующее: своё приложение вы делаете DDE-сервером, способным выполнять определённую команду, а в реестре при создании файловой ассоциации прописываете определённые параметры, и система благодаря этому будет знать, что ваша программа - DDE-сервер. И при открытии в Проводнике или через ShellExecute ассоциированного с ней файла система будет сначала пытаться использовать DDE, чтобы установить связь с уже запущенной копией приложения и передать файл ей. И только в случае неудачи будет запускать новый экземпляр приложения.
Хочу спросить у всех, кто советует использовать WM_CopyData или что-нибудь ещё: знаете ли вы, что именно нужно прописать в реестре, чтобы система знала о том, что ваше приложение умеет использовать WM_CopyData, и сама попыталась бы послать ей это сообщение, чтобы без необходимости не запускать новую копию программы? Подчёркиваю - именно прописать в реестре, без дополнительного кода по поиску/связи второго экземпляра приложения с первым? В случае с DDE я это знаю.
07-04-2006 01:52 | Комментарий к предыдущим ответам
Куфенко Павел:
Microsoft отказался от дальнейшего развития DDE, но в целях совместимости ряд системных механизмов продолжают его использовать, в т.ч. и тот механизм, о котором идёт речь в вопросе. И готовой альтернативы нет.
Вообще, при открытии файла в каком-либо приложении, имя этого файла и так передается в командной строке. Вы можете получить доступ к ней из программы, воспользовавшись переменными ParamCount и ParamStr
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.