Calling Shell32.dll from .NET Windows Service
本文关键字:Windows Service NET from Shell32 dll Calling | 更新日期: 2023-09-27 17:56:05
我有一个.NET 4.0库,它使用Shell32和Folder.GetDetailsOf()从WTV文件中获取元数据。 我已经成功地将其与控制台和 Windows 窗体应用程序一起使用,没有问题。 但由于某种原因,从 .NET 4.0 Windows 服务调用组件时,启动命令行管理程序类的调用会导致 COM 错误。
库中失败的代码:
Shell32.Shell shell = new Shell();
错误:
无法将类型为"System.__ComObject"的 COM 对象强制转换为接口类型"Shell32.Shell"。此操作失败,因为 COM 组件上对具有 IID'{286E6F1B-7113-4355-9562-96B7E9D64C54}' 的接口的 QueryInterface 调用失败,原因是出现以下错误:不支持此类接口(HRESULT 中的异常:0x80004002 (E_NOINTERFACE))。
我阅读了我的公寓线程,COM互操作,动态,PIA等,等等,等等:) 但是我找到的解决方案组合都没有解决这个问题。 它必须是来自另一个看不到互操作的线程的调用。 帮忙,请:)
我最近在使用命令行应用程序(控制台)时遇到了同样的问题。事实证明,需要使用 [STAThread]
属性注释程序的Main()
方法。还注意到,如果用[MTAThread]
注释入口点,它会以完全相同的方式惨遭失败。我希望它有所帮助。
我怀疑这可能与以下事实有关:默认情况下,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
我创建了一个Windows服务,并使用P/Invoke调用了Shell32。
就我而言,这是模拟右键单击文件:
首先,我需要创建一个以用户(而不是系统)身份与桌面交互的进程:
[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 的更多详细信息
由于我通过搜索错误找到了自己的方式,因此我想补充一点,如果您尝试从 GUI 应用程序中的非 gui 线程创建新的 Shell() 也会发生同样的事情 - 即使使用 [STAThread] 注释了 Main]。 @Eric J的回答给了我足够的暗示,让我从那里弄清楚。
因此,如果你想从GUI应用程序中获得Shell(),你需要做if(mainForm.InvokeRequired ) { mainForm.Invoke( ... ) } 跳舞。