簡體   English   中英

從.NET Windows服務調用Shell32.dll

[英]Calling Shell32.dll from .NET Windows Service

我有一個.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的線程的調用。 請幫忙 :)

最近我使用命令行應用程序(控制台)遇到了同樣的問題。 事實證明,需要使用[STAThread]屬性注釋程序的Main()方法。 還注意到,如果使用[MTAThread]注釋入口點,它將以完全相同的方式失敗。 我希望它有所幫助。

我懷疑這可能與以下事實有關:默認情況下,Windows服務沒有與桌面交互的權限。

要測試該理論,請重新配置(至少在臨時基礎上)您的服務權限以允許桌面交互。 以下鏈接指導您完成此操作

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

UPDATE

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(),即使Main用[STAThread注釋]也會發生同樣的事情。 ]。 @Eric J的答案給了我足夠的暗示從那里弄明白。

因此,如果您想從GUI應用程序中獲取Shell(),則需要執行if(mainForm.InvokeRequired){mainForm.Invoke(...)}舞蹈。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM