-1

I'm rewriting a small VB6 application/tool whose job is to install the latest version of some legacy VB6 app. The legacy VB6 app is an ActiveX DLL that's built and packaged into an executable installer (some Inno Setup script builds an installer by the name of companynameSetup.exe).

The legacy VB6 app being rewritten:

  • Kills all processes that consume the ActiveX DLL (across all logged users)
  • Uninstalls the current ActiveX DLL
  • Installs the new version of the ActiveX DLL
  • Can be executed with a command-line argument that disables UI

The rewritten C# app accomplishes all of the above as well. The only difference (apart from the fresh new look), is that regardless of with/without the UI, the VB6 code does not trigger any UAC prompt:

Shell(pathAndFileName, vbNormalFocus)

But this code does bring up UAC for the installer executable (the uninstaller runs first and doesn't prompt):

var startInfo = new ProcessStartInfo(path, args);
using (var process = Process.Start(startInfo))
{
    while (!process.HasExited && _timerTicks < _timeoutTicks) Thread.Sleep(100);

    //... (log stuff, handle timeout, etc.)
}

This is the log file after running as a scheduled task:

2013-06-12 21:49:00.8555 | Info | AutoDeploy.App | COMPUTER : somedomain\someadminuser | StartUp. ShowUI=False; TimeOut=100 | 
...
2013-06-12 21:50:40.4447 | Trace | AutoDeploy.App | COMPUTER : somedomain\someadminuser | Installer timer interval has elapsed (ticks: 99). | 
2013-06-12 21:50:41.4446 | Trace | AutoDeploy.App | COMPUTER : somedomain\someadminuser | Installer timer interval has elapsed (ticks: 100). | 
2013-06-12 21:50:41.4602 | Warn | AutoDeploy.App | COMPUTER : somedomain\someadminuser | Process execution has timed out. Process may be hung. | 

The process has to be stuck with UAC, because if I run it manually with the GUI, everything runs within a few seconds (after okaying UAC). So VB6 code can run unattended overnight, and the rewritten, new-and-improved (implements logging, failure notifications, all fun stuff!) C# app can't. So how does VB6 go under the radar?

So the question is, how do I schedule an installer to run unattended, without UAC messing things up? If scheduling the task is supposed to fix it, then how should the task be set up and is there anything special I need to add/remove from my assembly for it to work?

EDIT

The solution was simple:

var startInfo = new ProcessStartInfo(path, args) { UseShellExecute = False };
Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
  • It is pretty unclear what problem you are trying to solve. If it is "I don't want the UAC prompt" then, no, that's not an option. If it is "I don't need admin priviledges" then the name of your program matters. If it contains words like "setup" or "upgrade" then Windows is going to guess that it is the kind of program that might need elevation and shows the UAC prompt. You avoid that by including a manifest that uses "asInvoker". If it is "I'm getting a UAC prompt in unattended operation" then you solve that by using a scheduled task. – Hans Passant Jun 12 '13 at 13:47
  • @HansPassant sorry if I wasn't clear enough: "I don't want the UAC prompt", indeed. And if it's not an option, then how does VB6 code runs without triggering a UAC prompt for running the very same executable? I'll write the process-launching part in VB6 and call it in an `unsafe` block if I have to. But if there's no way around UAC then *how come I don't get a UAC prompt from the VB6 code running the exact same executable*? Is VB6 under-the-radar as far as UAC goes? – Mathieu Guindon Jun 12 '13 at 13:53
  • A VB6 program is treated like a legacy program because it doesn't have a manifest. Everything it does is *redirected* so it can't cause any trouble. Registry writes to HKLM are redirected to HKCU. File writes to protected directories are redirected to an isolated directory. If that program actually works then the odds that you actually *need* UAC elevation are very low. – Hans Passant Jun 12 '13 at 13:56
  • @HansPassant hold on here, I'm _not_ scheduling this program, specifically because I don't want the scheduled task hung waiting for UAC confirmation, are you saying that's something I don't need to worry about, that a scheduled task will not prompt UAC? If that's the case then thanks, problem solved (will try that right now!) - and thanks! (saying that the VB6 version actually works is somewhat of a stretch, but yeah, it "works") – Mathieu Guindon Jun 12 '13 at 14:00

1 Answers1

1

Like most things in the Framework, .Net's ProcessStartInfo class is a pretty big pile of... code. It wraps a ton of Win32 structures and calls.

Classic VB's Shell() function is a much lighter weight wrapper around WinExec() In Kernel32 which is in turn a thin wrapper around CreateProcess() In Kernel32 in 32 and 64 bit Windows.

I'm guessing what you really want is to start an external program using ProcessStartInfo without invoking the legacy installer detection heuristics in Shell32. There are two options i can think of:

  • Add a manifest to this second program marking it "Vista aware" via: <requestedExecutionLevel level="asInvoker" uiAccess="false"/>

  • Tell it not to use ShellExecute() but instead CreateProcess() by first setting: Process.UseShellExecute = false;

And "Yes Virginia, a VB6 program can (and should) have a manifest."

My C# being rusty, you might consult the docs: ProcessStartInfo.UseShellExecute Property

Bob77
  • 13,167
  • 1
  • 29
  • 37
  • Woot-woot! `UseShellExecute = false;` was all it took! Thanks a million! – Mathieu Guindon Jun 13 '13 at 02:24
  • `ShellExecute()` is also a wrapper around `CreateProcess()`, but with several layers of fat involved in between - including legacy installer detection. Glad this does what you need. – Bob77 Jun 13 '13 at 03:52