Как отправить ссылку на приложение, как это делает Spotify
Когда мы сохраняем уровень в нашем редакторе, мы создаем файл журнала всех ошибок, которые он содержит. Они состоят в основном из сообщения об ошибке и пути, который позволяет пользователю найти ошибочный элемент в древовидном представлении.
Я хочу сделать этот путь ссылкой, что-то вроде Нажмите, чтобы увидеть объект в редакторе a>
SO вопросы, которые я видел по этому поводу, похоже, указывают на эту страницу msdn: http://msdn.microsoft.com/en-us/library/aa767914.aspx
Но из того, что я могу сказать, появится новый экземпляр приложения. Что я хочу сделать, так это просто "позвонить" нашему редактору. Один из способов сделать это, я полагаю, состоит в том, чтобы вызвать его и в начале проверить, запущен ли уже экземпляр, и если да, отправьте ему командную строку.
Это лучший способ сделать это? Если да, есть идеи, как это сделать лучше всего? В противном случае, как это можно сделать?
Кроме того: решение MSDN работает в разных браузерах? Наш редактор работает только в Windows, но люди используют IE, Fx, GC и Opera.
3 ответа
Если вам нужна ссылка для работы в любом средстве просмотра, да, регистрация обработчика протокола - лучший способ.
Что касается запуска редактора, вы можете реализовать его как внепроцессный COM-сервер, но если у вас уже отсортирован синтаксический анализ командной строки, вы также можете использовать сообщение окна или именованный канал, чтобы передать его редактору. Если вы отправляете сообщение окна, вы можете использовать FindWindow (с уникальным именем класса) для проверки работающего экземпляра.
Похоже, вы уже решили это, проверив предыдущий экземпляр.
Я был бы удивлен, если бы ОС взяла на себя это как-то "помечать" связь с данными, сообщая об этом отдельным программам, которые должны запускаться несколько раз, из программ, которые не должны.
Вот как я это решил. В основном, есть две части. Или три.
Во-первых, приложение должно зарегистрироваться в реестре, как это. Потребовалось немного погуглить, чтобы выяснить, как использовать функции регистрации окон, но они были довольно просты. При добавлении этого в реестр ваше приложение будет запущено при нажатии на ссылку с вашим настраиваемым протоколом URL.
Во-вторых, приложение должно определить, что оно запущено из браузера. Очевидно, что это довольно тривиально, просто проверьте командную строку на "/uri" или, как вы решили ее настроить.
В-третьих, вы на самом деле не хотите запускать свое приложение - оно уже должно быть запущено! Вместо этого, когда вы обнаружили, что начали по гиперссылке, вам необходимо определить, запущен ли другой экземпляр приложения. После этого вам нужно передать ему командную строку. Вот как я это сделал:
bool ShouldContinueStartEditor( const std::string& command_line )
{
// Check if this instance was spawned from a web browser
if ( command_line.find( "/uri" ) != std::string::npos )
{
// Try to find other instance of JustEdit
HWND wnd = FindWindow( "AV_MainFrame", NULL );
if ( wnd )
{
COPYDATASTRUCT cds;
NEditorCopyData::SCommandLine data_to_copy;
strncpy( data_to_copy.m_CommandLine, command_line.c_str(), sizeof(data_to_copy.m_CommandLine) - 2 );
cds.dwData = NEditorCopyData::ECommandLine; // function identifier
cds.cbData = sizeof( data_to_copy ); // size of data
cds.lpData = &data_to_copy; // data structure
SendMessage( wnd, WM_COPYDATA, NULL, (LPARAM) (LPVOID) &cds );
}
return false;
}
return true;
}
"AV_Mainframe" - это имя hwnd. Если вы используете WTL, вы можете объявить это следующим образом.
DECLARE_FRAME_WND_CLASS("AV_MainFrame", IDR_MAINFRAME)
Теперь в вашем классе окна вам нужно обработать сообщение WM_COPYDATA следующим образом:
MESSAGE_HANDLER(WM_COPYDATA, OnCopyData);
LRESULT OnCopyData(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT CMainFrame::OnCopyData(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
PCOPYDATASTRUCT cds = (PCOPYDATASTRUCT) lParam;
if ( cds->dwData == NEditorCopyData::ECommandLine )
{
NEditorCopyData::SCommandLine* command_line = static_cast( cds->lpData );
const char* internal_path = strstr( command_line->m_CommandLine, "/uri" );
if ( internal_path != NULL )
{
// Do your thang
}
}
return 0;
}
И это почти все, что нужно. О, вот как выглядит пространство имен данных для копирования:
namespace NEditorCopyData
{
enum ECopyDataMessages
{
ECommandLine = 0
};
struct SCommandLine
{
char m_CommandLine[512];
};
}