Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What Difference Does UseShellExecute Have?

Tags:

c#

iis-7.5

I am starting a small console application from within my IIS web application. The code is started from within an app pool using code like this,

Process process = new Process();
ProcessStartInfo processStartInfo = new ProcessStartInfo();

processStartInfo.CreateNoWindow = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;

// ..

process.Start();

I used to intermittently get an error,

Win32Exception exception has occured  Message: No such interface supported
ErrorCode: 80004005  NativeErrorCode: 80004002

I proved that when this happened the console application wouldn't start at all.

I added to the code above this,

processStartInfo.UseShellExecute = false;

And the problem has gone away (so far, fingers crossed). I understand that by making this change it doesn't require a valid desktop context to run, but what exactly does that mean. If that means we cannot run the above code if there is no desktop (which applies to an IIS app pool running with a system user), then why did it used to run sometimes in the past rather than fail every time?

Does anybody have any idea why this would make a difference? What does no interface supported mean in this context?

UPDATE:

I have taken on board everything people have said, and done more research myself. So to summarise if you have UseShellExecute = true (which is the default) then it will call ShellExecuteEX in shell32.dll to execute the process. It will do this actually (copied from the System.dll using ILSpy),

public bool ShellExecuteOnSTAThread()
{
    if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
    {
        ThreadStart start = new ThreadStart(this.ShellExecuteFunction);
        Thread thread = new Thread(start);
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        thread.Join();
    }
    else
    {
        this.ShellExecuteFunction();
    }
    return this._succeeded;
}

If you have UseShellExecute = false then it will call CreateProcess in kernel32.dll to start the process.

I was wondering if there is a problem with the fact the the code ShellExecuteOnSTAThread above is creating a new thread? Could the app pool reach some limit on the threading which could indirectly cause a Win32Exception?

like image 243
peter Avatar asked Apr 19 '12 23:04

peter


1 Answers

This error can occur when certain COM objects aren't registered, although it's a bit of a mystery to me why it's intermittent.

In fairness though, Spawning a local executable from within IIS is a pretty rare thing to do and it may actually cause a security problem, or at the least cause an issue with IIS if the command fails for some reason and doesn't give control back to the system.

In reality the best practice for something like that is to record the action that you need to happen inside the registry,database or some kind of setting file and have your local application run as a scheduled task or a windows service.

For reference, the UseShellExec states whether or not the Kernel should launch the exe directly, or whether it should ask Explorer to launch the file.

You might be getting this problem when there's no-one logged in so there isn't necessarily a shell loaded to launch the exe.

Ultimately though, what you're currently trying to do is a bad thing in production - you cannot guarantee the state of IIS when it tries to launch this exe and rightly so, IIS is not a Shell.

like image 138
Russ Clarke Avatar answered Oct 04 '22 11:10

Russ Clarke