当作为远程桌面应用程序运行时,Delphi TOpenDialog 在 Windows 2008 中挂起

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3206010/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 14:47:23  来源:igfitidea点击:

Delphi TOpenDialog hangs in windows 2008 when run as remote desktop application

windowsdelphirda

提问by Bill Seven

I have a Delphi 2010 exe that launches a second exe. In the second exe, there is a dialog that calls openDialog.execute. When this runs under Windows 2008 Enterprise R2 under a remote desktop, it runs as expected, but when run as a remote application, as soon as the file dialog pops up, the application hangs, turning all of the application windows white. The only way to get out of it is to terminate the application. I tried replacing TOpenDialog with TFileOpenDialog, the results are the same. I've looked into modifying the RDP file that launches the main application, but cannot see any parameters there that would make a difference. Has anyone ever seen this kind of behavior before?

我有一个 Delphi 2010 exe 可以启动第二个 exe。在第二个 exe 中,有一个调用 openDialog.execute 的对话框。当它在远程桌面下的 Windows 2008 Enterprise R2 下运行,它按预期运行,但是当作为远程应用程序运行时,一旦弹出文件对话框,应用程序就会挂起,将所有应用程序窗口变成白色。摆脱它的唯一方法是终止应用程序。我尝试用 TFileOpenDialog 替换 TOpenDialog,结果是一样的。我已经研究过修改启动主应用程序的 RDP 文件,但在那里看不到任何会产生影响的参数。有没有人见过这种行为?



2010.07.13 Updated

2010.07.13 更新

This is reproducable using a simple example. There are two executable files in the example. The first is a file launcher, called m_module.exe, which contains one edit, one button, and the code below. I change the name of the executable file in the edit to match the second executable before I click the launch button:

这可以使用一个简单的示例重现。示例中有两个可执行文件。第一个是文件启动器,名为 m_module.exe,其中包含一个编辑、一个按钮和以下代码。在单击启动按钮之前,我在编辑中更改可执行文件的名称以匹配第二个可执行文件:

procedure TForm1.Button1Click(Sender: TObject);
begin
     ShellExecute(Handle, 'open', stringToOLEstr(edit1.text) , nil, nil, SW_SHOWNORMAL) ; 
end;

procedure TForm1.FormShow(Sender: TObject);
begin
     edit1.text:=application.exename;
end;

The second executable contains a button and the code below:

第二个可执行文件包含一个按钮和以下代码:

procedure TForm1.Button1Click(Sender: TObject);
begin
     OpenDialog1.execute;
end;

The first module is launched from an RDP file.

第一个模块从 RDP 文件启动。

2010.07.14 Updated

2010.07.14 更新

I have discovered that if I copy the following dlls:

我发现如果我复制以下 dll:

thumbcache.dll 
dtsh.dll 
wkscli.dll 

from the \Windows\System32 folder into the application folder, the problem is eliminated.

从\Windows\System32文件夹进入应用程序文件夹,问题就解决了。

I've further discovered that changing ownership and permission levels of these dlls in the \Windows\System32 folder from TrustedInstaller to the Administrator's group has the same result (Copying them to the application directory is changing ownership and permission I think)

我还发现将 \Windows\System32 文件夹中这些 dll 的所有权和权限级别从 TrustedInstaller 更改为管理员组具有相同的结果(我认为将它们复制到应用程序目录正在更改所有权和权限)

To confirm this, I verified that the errors reappeared if I changed the ownership and permission levels back to TrustedInstaller away from the Administrator's group.

为了确认这一点,我验证了如果我将所有权和权限级别从管理员组更改回 TrustedInstaller,错误会再次出现。

So it appears that this is an access issue of some kind. Perhaps this will help in discovering the cause of the issue.

因此,这似乎是某种访问问题。也许这将有助于发现问题的原因。

2010.07.18 Updated

2010.07.18 更新

Some additional information that might be helpful (provided by Embarcadero):

一些可能有用的附加信息(由 Embarcadero 提供):

This MSDN article for GetWindowsDirectory http://msdn.microsoft.com/en-us/library/ms724454%28VS.85%29.aspxdocuments some interesting behavior of applications running under Terminal Services. While GetWindowsDirectory is not being called directly the sandboxing of the Windows System directory per user could be causing some sort of problem. Perhaps one of the DLLs in the calling chain to GetOpenFileNameA is trying to reference the real DLL in the real System directory instead of the sandboxed one thus causing a rights violation. It is just speculation but it is worth investigating. If you were able to get the SysInternals Process Monitor or Process Explorer working on the server you should be able to see commdlg32 and the other DLLs in the stack trace being loaded.

GetWindowsDirectory 的这篇 MSDN 文章http://msdn.microsoft.com/en-us/library/ms724454%28VS.85%29.aspx记录了在终端服务下运行的应用程序的一些有趣行为。虽然 GetWindowsDirectory 没有被直接调用,但每个用户的 Windows 系统目录沙箱可能会导致某种问题。也许 GetOpenFileNameA 调用链中的一个 DLL 试图引用真实系统目录中的真实 DLL,而不是沙盒中的 DLL,从而导致权利侵犯。这只是猜测,但值得研究。如果您能够让 SysInternals Process Monitor 或 Process Explorer 在服务器上工作,您应该能够看到正在加载的堆栈跟踪中的 commdlg32 和其他 DLL。

All legacy applications (i.e. all applications not created for Terminal Services or Remote Desktop Services) run under an Application Compatibility Layer. See this MSDN article http://msdn.microsoft.com/en-us/library/cc834995%28VS.85%29.aspx. The IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE flag is defined in Windows.PAS. For testing purposes you can add it to your application's PE header by adding Windows to your application's USES section and right under the USES section put:

所有遗留应用程序(即不是为终端服务或远程桌面服务创建的所有应用程序)都在应用程序兼容层下运行。请参阅此 MSDN 文章http://msdn.microsoft.com/en-us/library/cc834995%28VS.85%29.aspx。IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 标志在 Windows.PAS 中定义。出于测试目的,您可以通过将 Windows 添加到应用程序的 USES 部分并在 USES 部分下方放置:

{$SetPEOptFlags IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE}

{$SetPEOptFlags IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE}

This will cause your application to bypass the compatibility layer. I am currently investigating if spawned processes (e.g. your second exe) retain all of the rights and settings of the application defined under RDS.

这将导致您的应用程序绕过兼容层。我目前正在调查生成的进程(例如您的第二个 exe)是否保留了在 RDS 下定义的应用程序的所有权限和设置。

回答by Alex

Windows reports AV (c0000005) in thumbcache.dll module.

Windows 在 thumbcache.dll 模块中报告 AV (c0000005)。

I think that thumbcache.dll have something to do with building/caching thumbnails for files. Building thumbnails may mean using 3rd party extensions to Explorer, which may not behave nicely with RDP.

我认为 thumbcache.dll 与构建/缓存文件缩略图有关。构建缩略图可能意味着使用资源管理器的 3rd 方扩展,这可能与 RDP 表现不佳。

Try that on clean system. Use VMWare or similar virtual machine to setup test configuration.

在干净的系统上试试。使用 VMWare 或类似的虚拟机来设置测试配置。

P.S. See also this article: How to debug application's hang?But I think that hang is just consequence of another problem in your case.

PS另见这篇文章:如何调试应用程序的挂起?但我认为挂起只是你的情况下另一个问题的结果。

回答by Chris Thornton

FWIW, we have a similar situation, but it's driven by a security need, and not a crash. When our app runs via Citrix, we are forbidden to ever show the regular windows "open" or "save as" dialogs. So we rolled our own. It's got a combo of drive letters (local drives only), folder selector (restricted to the approved drives), filename selector, and filename edit box.

FWIW,我们有类似的情况,但它是由安全需求驱动的,而不是崩溃。当我们的应用程序通过 Citrix 运行时,我们被禁止显示常规窗口“打开”或“另存为”对话框。所以我们推出了自己的。它有驱动器号(仅限本地驱动器)、文件夹选择器(仅限于批准的驱动器)、文件名选择器和文件名编辑框的组合。

For us, this gets around any active directory issues, and keeps security happy. And it keeps the users from trying to drop files into our filesystem or see things they shouldn't.

对我们来说,这可以解决任何活动目录问题,并保持安全性。它可以防止用户尝试将文件放入我们的文件系统或看到他们不应该看到的东西。

If they're not running in the sandbox, we show the regular windows file dialogs. A wrapper function allows us to call it from anywhere and leave the "sandboxed vs windows" decision in one spot.

如果它们不在沙箱中运行,我们会显示常规的 Windows 文件对话框。包装函数允许我们从任何地方调用它,并将“沙盒与 Windows”的决定留在一个地方。

回答by Name

You seems to have narrowed your problem to an access issue of some kind, so the following explanation might not help you. But there seems to exist a problem with popup windows on RemoteApp and I could imagine that it could lead (at least theoretically) to a similar problem, that's why I would like to mention it: http://social.technet.microsoft.com/Forums/en-US/winserverTS/thread/0a88919f-2d72-4340-abd7-fbe0e9545f25/

您似乎已将问题缩小到某种访问问题,因此以下解释可能对您没有帮助。但是 RemoteApp 上的弹出窗口似乎存在问题,我可以想象它可能会(至少在理论上)导致类似的问题,这就是我想提及它的原因:http: //social.technet.microsoft.com /Forums/en-US/winserverTS/thread/0a88919f-2d72-4340-abd7-fbe0e9545f25/

Apparently the Z-order of the windows isn't always correct when using RemoteApp. In your case TOpenDialog should be a modal popup window. Due to the bug, I could imagine that TOpenDialog could appear in the background. Your main window would remain in the foreground but would be disabled as TOpenDialog is modal. Windows might then not know how to redraw a disabled window and simply draw a white box.

显然,使用 RemoteApp 时,窗口的 Z 顺序并不总是正确的。在您的情况下, TOpenDialog 应该是一个模态弹出窗口。由于这个错误,我可以想象 TOpenDialog 可能会出现在后台。您的主窗口将保留在前台,但会被禁用,因为 TOpenDialog 是模态的。Windows 可能不知道如何重新绘制禁用的窗口,而只是绘制一个白框。

回答by Dangas56

We were having problems on the OpenDialog.Execute but only on one computer - and it seemed to be random I found that adding the exe the Windows DEP may resolve the problem we haven't had any issues since changing it

我们在 OpenDialog.Execute 上遇到了问题,但仅在一台计算机上遇到了问题 - 这似乎是随机的

here is the link on how to change the windows DEP settings http://www.itechtalk.com/thread3591.html

这是有关如何更改 Windows DEP 设置的链接 http://www.itechtalk.com/thread3591.html

this is a workaround - if anyone knows how to keep the DEP happy please add a comment below

这是一种解决方法 - 如果有人知道如何让 DEP 满意,请在下面添加评论

回答by Henrik Carlsen

It the Z-order is incorrect (which I often see in Citrix, without having a proper fix to it) you would still be able to close the form with ctrl-F4 or alt-f4. Furthermore the application would not be "not responding". Sometimes the order will correct itself when switching between tasks

如果 Z 顺序不正确(我经常在 Citrix 中看到,没有对其进行适当修复),您仍然可以使用 ctrl-F4 或 alt-f4 关闭表单。此外,应用程序不会“无响应”。有时在任务之间切换时顺序会自行纠正

回答by Alex

I recommend you to use Process Explorertool to view properties of your process. Check, which exactly DLLs are loaded in both cases (you can do it by selecting your process and opening lower pane in modules view).

我建议您使用Process Explorer工具来查看您的流程的属性。检查在这两种情况下究竟加载了哪些 DLL(您可以通过选择您的进程并在模块视图中打开下部窗格来完成)。

You can also use Process Monitortool to monitor process startup (again: in both cases) and see any references to DLLs in question.

您还可以使用进程监视器工具来监视进程启动(同样:在这两种情况下)并查看对相关 DLL 的任何引用。