10

我有一个 .NET 4.0 库,它使用 Shell32 和 Folder.GetDetailsOf() 从 WTV 文件中获取元数据。我已经成功地将它与控制台和 Windows 窗体应用程序一起使用,没有问题。但由于某种原因,当从 .NET 4.0 Windows 服务调用组件时,启动 Shell 类的调用会导致 COM 错误。

库内失败的代码:

Shell32.Shell shell = new Shell();

错误:

无法将“System.__ComObject”类型的 COM 对象转换为接口类型“Shell32.Shell”。此操作失败,因为 IID 为“{286E6F1B-7113-4355-9562-96B7E9D64C54}”的接口的 COM 组件上的 QueryInterface 调用因以下错误而失败:不支持此类接口(来自 HRESULT 的异常:0x80004002 (E_NOINTERFACE)) .

我阅读了我的 Apartment Threading、COM Interops、Dynamic、PIA 等 等 :) 但我找到的解决方案组合都没有解决这个问题。它必须是来自另一个看不到互操作的线程的调用。请帮忙 :)

4

4 回答 4

14

我最近在使用命令行应用程序(控制台)时遇到了同样的问题。事实证明,需要用属性注释程序的Main()方法。[STAThread]还注意到,如果入口点被注释了,它会以完全相同的方式失败[MTAThread]。我希望它有所帮助。

于 2014-07-26T03:38:59.513 回答
3

我怀疑这可能与默认情况下 Windows 服务无权与桌面交互的事实有关。

要测试该理论,请重新配置(至少临时)您的服务权限以允许桌面交互。以下链接将引导您完成此操作

https://superuser.com/questions/415204/how-do-i-allow-interactive-services-in-windows-7

更新

Shell32 功能与 LocalSystem 一样工作得很好,即使未选中“允许服务与桌面交互”复选框,但在特定用户帐户(无论是受限用户帐户还是管理员帐户)下似乎根本不起作用

在 Windows 服务中使用 SHFileOperation

如果你成功地让它工作,请确保你禁止任何 UI 交互。此答案中提供了有关如何执行此操作的信息:

https://stackoverflow.com/a/202519/141172

于 2013-01-27T01:03:32.170 回答
0

我创建了一个 Windows 服务,并使用 P/Invoke 调用了 Shell32。

就我而言,它是模拟右键单击文件:

首先,我需要以用户(而不是系统)的身份创建一个进程来与 Desktop 进行交互:

[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Auto)]
 static extern bool CreateProcessAsUser(
     IntPtr hToken,
     string lpApplicationName,
     string lpCommandLine,
     ref SECURITY_ATTRIBUTES lpProcessAttributes,
     ref SECURITY_ATTRIBUTES lpThreadAttributes,
     bool bInheritHandles,
     uint dwCreationFlags,
     IntPtr lpEnvironment,
     string lpCurrentDirectory,
     ref STARTUPINFO lpStartupInfo,
     out PROCESS_INFORMATION lpProcessInformation);

在这个过程中,我使用了 Shell32 库(加载然后提取值)

[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax);

我的 Windows 服务可以通过它找到 Shell32 的不同值并像用户一样与桌面交互;-)

您可以在此网站上找到 P/Invoke 的更多详细信息

于 2013-05-17T09:21:55.783 回答
0

因为我通过搜索错误找到了我的方式,所以我想补充一点,如果您尝试从 GUI 应用程序中的非 gui 线程创建一个新的 Shell(),也会发生同样的事情 - 即使 Main 被注释为 [STAThread ]。@Eric J 的回答给了我足够的暗示,让我从那里弄清楚。

因此,如果您想要 GUI 应用程序中的 Shell(),则需要执行 if(mainForm.InvokeRequired) { mainForm.Invoke( ... ) } 舞蹈。

于 2018-05-25T00:24:44.530 回答