Calling Shell32.dll from .NET Windows Service

百般思念 提交于 2019-12-01 03:23:51

I had the same problem just recently with a command line application (console). Turns out, it was required to annotate the program's Main() method with the [STAThread] attribute. It has also been noted that it fails miserably in the exact same way if the entry point is annotated with [MTAThread] instead. I hope it helps.

Eric J.

I suspect this may be related to the fact that, by default, a Windows Service does not have permission to interact with the desktop.

To test that theory, reconfigure (at least on a temporary basis) your service permissions to allow for desktop interaction. The following link walks you through doing that

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

UPDATE

The Shell32 functionality works just fine as LocalSystem, even when the "Allow service to interact with desktop" checkbox is unchecked, but doesn't seem to work at all under a specific user account (whether limited or admin)

Using SHFileOperation within a Windows service

If you succeed in getting this to work, make sure that you suppress any UI interaction. Information on how to do that is available in this answer:

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

I have created a Windows Service and I called Shell32 with P/Invoke.

In my case, it was to simulating the right click on file :

First, I need to create a process as user (not System) to interact with 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);

And in this process, I used the Shell32 Library (load then extract the value)

[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);

My Windows Service can find the differents values of Shell32 with this and interact with the desktop like user ;-)

You can find more details for P/Invoke on this website

Since I found my way here by searching for the error, I wanted to add that the same thing happens if you try to make a new Shell() from a non-gui thread in a GUI app - even when Main is annotated with [STAThread]. @Eric J's answer gave me enough of a hint to figure it out from there.

So if you want Shell() from a GUI app, you need to do the if( mainForm.InvokeRequired ) { mainForm.Invoke( ... ) } dance.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!