如何发送应用程序的链接,如 Spotify 那样

发布于 2024-07-18 03:00:10 字数 627 浏览 8 评论 0原文

当我们在编辑器中保存关卡时,我们会创建一个包含它包含的所有错误的日志文件。 这些基本上由错误消息和允许用户在树视图中找到错误项目的路径组成。

我想要的是使该路径成为一个链接,例如 < a href="editor://path/to/gameobject" > 单击以在编辑器中查看对象< /a>

我看到的关于此问题的SO问题似乎指向这个msdn页面: http://msdn.microsoft.com/en-us/library/aa767914。 aspx

但据我所知,它将生成应用程序的一个新实例。 我想做的就是以某种方式简单地“调用”我们的编辑器。 我想,一种方法是生成它,并在开始时检查是否已经有一个实例正在运行,如果是,则将命令行发送给它。

这是最好的方法吗? 如果是这样,有什么想法可以做到最好吗? 还有什么其他方法可以做到这一点?

另外:msdn 解决方案可以跨浏览器工作吗? 我们的编辑器仅在 Windows 中运行,但人们使用 IE、Fx、GC 和 Opera。

When we save a level in our editor, we create a log file of any errors it contains. These consist basically of an error message and a path that allows the user to find the erronous item in a tree view.

What I want is to make that path a link, something like
< a href="editor://path/to/gameobject" > Click to see object in editor< /a >

The SO questions I've seen regarding this seems to point to this msdn page:
http://msdn.microsoft.com/en-us/library/aa767914.aspx

But from what I can tell, it will spawn a new instance of the application. What I want to do is to simply "call" our editor somehow. One way to do it, I guess, is to spawn it, and in the beginning check if there's already an instance running, and if so, send the commandline to it.

Is that the best way to do it? If so, any ideas on how to do it best? What are otherwise some ways that this could be done?

Also: does the msdn solution work across browsers? Our editor runs in Windows only, but people use IE, Fx, GC and Opera.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦开始←不甜 2024-07-25 03:00:10

如果您需要链接在任何查看器中工作,是的,注册协议处理程序是最好的方法。

至于启动编辑器,您可以将其实现为 进程外 COM服务器,但如果您已经对命令行解析进行了排序,您不妨使用 窗口消息或命名管道将其传递给编辑器。 如果您要发送窗口消息,可以使用 FindWindow (具有唯一的类名)来检查正在运行的实例。

If you need the link to work in any viewer, yes, registering a protocol handler is the best way.

As for launching the editor, you could implement it as an out-of-process COM server, but if you've already got command line parsing sorted, you might as well use a window message or named pipe to pass that to the editor. If you're sending a window message, you could use FindWindow (with a unique class name) to check for a running instance.

起风了 2024-07-25 03:00:10

听起来你已经通过检查以前的实例解决了这个问题。

如果操作系统以某种方式“标记”与数据的关联,告诉它将应该多次运行的程序与不应该多次运行的程序分开,我会感到惊讶。

Sounds like you solved it already, by checking for a previous instance.

I would be surprised if the OS takes upon it to somehow "stamp" the association with data telling it to separate programs that should run multiple times from programs that should not.

[旋木] 2024-07-25 03:00:10

我是这样解决的。 基本上有两个部分。 或者三个。

首先,应用程序需要在注册表中注册自身,如下所示。 花了一些谷歌搜索才找到如何使用 Windows 寄存器函数,但它们非常简单。 通过将其添加到注册表,当单击带有自定义 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];
 };

}

Here's how I solved it. Basically, there are two parts. Or three.

First, the app needs to register itself in the registry, like this. It took some googling to find out how to use the windows register functions, but they were pretty straightforward. By adding this to the registry, your application will launch when a link with your custom url protocol is clicked.

Secondly, the app needs to detect that it's been started from a browser. Obviously quite trivial, just check the command line for "/uri" or however you chose to customize it.

Third, you don't actually want to start your application - it should already be running! Instead, when you've detected that you got started from a hyperlink, you need to detect if another instance of the application is already running. After that, you need to pass the command line to it. Here's how I did it:

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" is the name of the hwnd. If you happen to be using WTL, you can declare it like this.

DECLARE_FRAME_WND_CLASS("AV_MainFrame", IDR_MAINFRAME)

Now, in your window class, you need to handle the WM_COPYDATA message like this:

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;
}

And that's pretty much all there's to it. Oh, this is what the copy data namespace looks like:

namespace NEditorCopyData
{
 enum ECopyDataMessages
 {
  ECommandLine = 0
 };

 struct SCommandLine
 {
  char m_CommandLine[512];
 };

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文