为什么在资源管理器中打开与我们的应用程序关联的文件时出现DDE错误?

时间:2017-08-22 22:45:45

标签: visual-c++ mfc windows-explorer dde

我们的旧MDI桌面应用程序使用关联中的/dde开关。打开与其关联的文件且应用程序尚未启动时,资源管理器会弹出以下错误:

There was a problem sending the command to the program.

注册表看起来像这样:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document]
@="App File"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\DefaultIcon]
@="d:\\Program Files (x86)\\MyApp\\version\\app.exe,1"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\open]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\open\command]
@="\"C:\\Program Files\\App\\app.exe\" /dde"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\open\ddeexec]
@="[open(\"%1\")]"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\print]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\print\command]
@="C:\\Program Files\\App\\app.exe /dde"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\print\ddeexec]
@="[print(\"%1\")]"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\printto]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\printto\command]
@="C:\\Program Files\\App\\app.exe /dde"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\App.Document\shell\printto\ddeexec]
@="[printto(\"%1\",\"%2\",\"%3\",\"%4\")]"

为了清楚起见,我刚从注册表中获取了这些条目。我不太了解他们做了什么,但我可以冒险猜测他们通过DDE interface将动词与动作联系起来。

请注意,如果应用程序已经启动,则该文档在该实例中打开正常。如果应用程序尚未启动并且必须执行应用程序的新实例,则这只是一个问题。

所以,发生的事情是通过双击打开关联文件,然后执行关联的应用程序。然后Explorer将弹出该消息,我们的应用程序将不执行任何操作。再次双击该文件将打开该文档。

我们以前遇到过这个问题,但是我们决定忽略它几年,因为没有人真正知道它是什么,我们当时还有其他优先事项。我们的解决方法是告诉用户将/dde更改为"%1"。是的,跛脚,但它运作良好。这样做的一个问题是,无论应用程序是否已经运行,它都会执行应用程序的新实例。

无论如何,这个问题现在开始成为一个实际问题,需要修复。我们的一位开发人员说DDE系统已经过时,我们应该尝试编写一个COM组件,它将像Visual Studio一样重定向到我们的应用程序,因为调试此问题可能需要一段时间。我还没有验证,也没有研究过多少努力。然而,无论是在调试方面还是在研究方面,要么可能是资源密集型,所以我试图做一些初步研究,看看我能挖掘什么,并确定哪种方法更好。

踩到代码,我能够确定它进入::SetWindowPlacement()调用并踩到它会导致弹出错误消息框(如果资源管理器没有先超时)。由于它是一个WINAPI,我无法进入该功能,看看它在做什么。

应用程序主要使用MFC / API和其他库在VC / VC ++中编写。

所以我的问题是,有谁知道为什么会这样,以及如何解决?

修改

其他一些信息:

我能够非破坏性地拦截所有SendMessage() / PostMessage() / DispatchMessage()函数调用,这将记录所有消息。这是通过使用MS Detours 3.0实现的。

我看到的是,有4条SendMessage来电,其中WM_COPYDATA消息似乎来自shell32.dll。但是,它似乎并不是有问题的消息。

在检测到__debugbreak()消息时设置WM_COPYDATA会导致错误,直到超出几步。多远取决于我是否步骤或者我是否设置断点并将代码运行到我认为我收到错误之外的某个地方。使用DebugBreak()似乎会使调试程序变慢,以至于我无法在不显示错误的情况下执行此操作。

我无法理解的是,对于触发弹出错误消息的内容,似乎没有任何押韵或理由。我似乎没有超时,因为超时似乎很长,直到我开始踩代码,有时代码没有发送/发布消息。因此,没有WM_DDE_ACK(或任何关于此问题的消息)被发送回启动了此窗口的资源管理器窗口。这非常令人沮丧。

为了进一步复杂化,如果我使用内部__debugbreak()调用并且我在代码中的其他地方有一个断点,它有时可以在该断点处停止而不是停在__debugbreak()。有时候,当我控制调试器时立即运行代码时,它有时会导致第二次中断,就像它击中另一个__debugbreak()一样。那是什么一回事?不一致的调试肯定会使这个问题更难以追查。 >:(

2 个答案:

答案 0 :(得分:0)

  1. 此DDE内容仍然用于MDI接口。因此,如果一个EXE打开不同的文件。
  2. 如果你可以多次启动你的应用程序,这没关系,对于客户来说,将注册表中的条目切换到SDI中的正常占位符也是可以的。
  3. 如果EXE在特定时间内没有准备好接受DDE命令,通常会从资源管理器中显示此消息。
  4. 因此,您面临的主要问题是:应用程序中未检索到DDE消息的内容有何变化或如此缓慢。

    如果在消息循环开始之前需要很长时间才会出现这种情况。 DDE支持需要主窗口的运行消息循环。

    SetWindowPos本身不会出现问题,但它可能会导致数百条消息(WM_SIZE,...)被触发到您的应用程序,并且您的应用程序中的每个处理程序都可能出现问题。

    只需在SetWindowPos前面的应用程序中放置一个小计时器,并检查返回所需的时间......

    检查应用程序需要多长时间,直到InitInstance退出为TRUE。在InitInstance退出CWinApp :: Run之后,消息循环开始。

答案 1 :(得分:0)

我遇到了同样的问题。

我的解决方案是在应用程序启动时在注册表中添加../ddeexec/*部分,然后在应用程序退出时删除它们。

这不是一个非常好的解决方案,但它很容易做到,并且有效。