从.NET Windows服务调用Shell32.dll

时间:2013-01-27 00:57:48

标签: c# .net multithreading com shell32

我有一个.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))

我阅读了我的公寓线程,COM Interops,动态,PIA等等,但是我找到的解决方案没有解决问题。它必须是来自另一个无法看到Interop的线程的调用。请帮助:)

4 个答案:

答案 0 :(得分:14)

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

答案 1 :(得分:3)

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

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

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

<强>更新

  

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

Using SHFileOperation within a Windows service

如果您成功实现此功能,请确保禁止任何UI互动。有关如何执行此操作的信息,请参阅以下答案:

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

答案 2 :(得分:0)

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

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

首先,我需要创建一个以用户(而不是System)与桌面交互的流程:

[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的不同值,并像用户一样与桌面交互; - )

您可以在此website

上找到有关P / Invoke的更多详细信息

答案 3 :(得分:-1)

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

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