2

We ran into problems with code that already worked to elevate the rights of a helper process that installs a new printer.

I found this answer here, which nearly matches our code: Windows 7 and Vista UAC - Programmatically requesting elevation in C#

The only difference is that we had set ShellExecute to false. This caused a Win32Exception that the process requires elevated rights. Use ShellExecute solved this.

My question is: why? Most likely there is an answer to that that makes sense and would really to understand what happens so I will know next time something similar is required.

Many thanks in advance for all hints!

Community
  • 1
  • 1
philip
  • 321
  • 3
  • 19
  • The basic "why" is that there's a significant problem with that "helper process". It should ask for elevation itself. – Hans Passant Oct 15 '13 at 14:17

3 Answers3

3

The way to elevate a new process programmatically is to ask the shell to execute the executable file using the verb runas. That's the only supported way to do it. In order to pass the runas verb to the shell, you need to call a suitable Win32 API function. Possible candidates include ShellExecute and ShellExecuteEx.

The UseShellExecute property determines which API call is used when you call Process.Start. If UseShellExecute is true, then ShellExecuteEx is called. Otherwise CreateProcess is called.

So, when you set UseShellExecute to false, you switched to using CreateProcess. And CreateProcess does not have any mechanism to elevate the new process. So when UseShellExecute is false, the runas verb that you provided is simply ignored because CreateProcess does not receive shell verbs.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
2

The behaviour is because Process.Start uses one of two APIs internally: CreateProcess or ShellExecuteEx. Only the latter supports UAC elevation, which us why you must set UseShellExecute = true.

As an interesting aside, there is another way to achieve UAC elevation without directly starting a new process. You can write an out-of-process COM component to perform the actual work that needs to run elevated. Then, when you instantiate the component, it runs in an elevated process (after the UAC prompt is displayed). Of course, it's not easy to write out-of-process COM components in .NET without using C++/CLI. But see this post for more information.

Community
  • 1
  • 1
Olly
  • 5,966
  • 31
  • 60
  • You second paragraph is wrong in that it only applies to special DLLs: "it must be digitally signed by the Windows publisher, which is the certificate used to sign all code included with Windows (it's not sufficient to be signed by Microsoft, so Microsoft software that's not shipped in Windows isn't included)" - so this is pretty exclusive. – coderforlife Aug 27 '15 at 05:15
  • @coderforlife - Thanks for spotting the mistake! The technique does work, but I hastily linked an article that describes something else altogether. I've put a link to another SO post instead. Hopefully this will be helpful to someone. – Olly Aug 31 '15 at 14:38
  • Awesome! I am glad that it does indeed work and will now look into using it (I read the article initially because I did want it to work). Thanks! – coderforlife Aug 31 '15 at 19:02
1

Microsoft Channel 9 video that explains the guts of UAC.

Architecturally, only ShellExecute has the knowledge of how to launch Consent.exe (the UAC dialog). So that's why you must use it.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219