Skip to content
⌘ NSIS Forum Archive

ShellExecAsUser plugin

28 posts

installer32#

ShellExecAsUser plugin

I've created a new ShellExecAsUser plugin:

It allows to execute the specified program in non-admin context, i.e. it is intended for installers that run with admin rights but need to execute something in non-admin context.
It uses desktop COM interface to execute process, so that process is launched by explorer (http://brandonlive.com/2008/04/27/ge...ou-part-2-how/).
Any comments are welcome.
LoRd_MuldeR#
Sound like something that can pretty useful 😎

Two questions:
* What operating systems does it work with? Any "fall back" mode for WinXP and Win2k?
* Can you please compile a Unicode version of that plug-in?

(Sorry, did not have time to examine your code yet)

Regards,
MuldeR.
installer32#
* What operating systems does it work with? Any "fall back" mode for WinXP and Win2k?
It should work starting from Win2k. On WinXP, Win2k (or if UAC is disabled) the plugin will do the launch using ShellExecute.

* Can you please compile a Unicode version of that plug-in?
Ok I'll do.
LoRd_MuldeR#
I have adopted your ExecShellAsUser method into my StdUtils plug-in:


(ANSI and Unicode builds attached)
MSG#
So, what, does this do what the UAC plugin was also designed to do, but without two installer instances?
LoRd_MuldeR#
Originally Posted by MSG View Post
So, what, does this do what the UAC plugin was also designed to do, but without two installer instances?
Yup. It generates a non-elevated process right from the elevated installer instance.

Seems to work for me on Windows 7 (x64). I don't have any other UAC-enabled test platforms.

On Windows XP and earlier it simply falls back to the normal ShellExecute()...
installer32#
I have adopted your ExecShellAsUser method into my StdUtils plug-in:
Ok but note that I used another thread for desktop COM calls. Otherwise I (sometimes) got RPC_E_CANTCALLOUT_ININPUTSYNCCALL error, which is solved if you do it on another thread.
LoRd_MuldeR#edited
Originally Posted by installer32 View Post
Ok but note that I used another thread for desktop COM calls. Otherwise I (sometimes) got RPC_E_CANTCALLOUT_ININPUTSYNCCALL error, which is solved if you do it on another thread.
Thanks for the hint!

(I already noticed that CoInitializeEx() fails, because, I think, COM already is initialized with other parameters for the calling thread. So I switched back to CoInitialize() again. But I will implement your suggestion now)

[UPDATE] Done. New version is attached. [/UPDATE]
MSG#
Very cool! I use the UAC plugin for double install mode all-through, for which case I guess it is more convenient to have two instances. But this is a very cool alternative, and a lot simpler to use!
LoRd_MuldeR#edited
Small update:
LoRd_MuldeR#
Sorry, here are some more fixes:
Anders#
This COM hack is problematic and/or broken when:

A)
Explorer is not running

B)
Explorer is elevated (Rare, but some people do it)

C)
Desktop user is not the correct parent:
User A is logged on,
runs setup as non-admin user B with runas.exe,
setup is elevated with user C;
The correct user is B, not A.
LoRd_MuldeR#
In case (A) it will fall back to the normal ShellExecute(). Not ideal, but well...

I'm not sure what will happen in case (B) or how to reproduce this, but I guess in that case we will either fail to get the COM interface and thus fall back to the normal ShellExecute(), or we will simply create an elevated instance.

Again not ideal, but if you run your Explorer in an elevated way, then problems are preprogrammed anyway 🙄

(And in case (C) it may depend on the situation/purpose whether user A or B is the "correct" one)
installer32#
Anders
You are right and I'll add your remarks to plugin description, though I think it's quite uncommon and as such these limitations are acceptable to many people.
LoRd_MuldeR#
I have updated my StdUtils plug-in to use the "new" plug-in API, i.e. get rid of explicit unload.

Furthermore I added a version of ExecShell with wait capability as well as some more convenience functions.

New version here:


(BTW: Could some mod please delete the obsolete versions attached to my previous posts?)
LoRd_MuldeR#
In case somebody is interested, I just uploaded a new version of my StdUtils plug-in:
LoRd_MuldeR#
Originally Posted by LoRd_MuldeR View Post
In case somebody is interested, I just uploaded a new version of my StdUtils plug-in:
http://nsis.sourceforge.net/StdUtils_plug-in
I've just uploaded yet another update, which fixes a potential crash related to CoUninitialize() and certain certain Shell Extensions. In my case it was Tortoise GIT. Put simply, CoUninitialize() might still crash, even if all COM interfaces were released properly before. Happens if there are outstanding messages. It turns out we must dispatch all pending messages explicitly before calling CoUninitialize().

As this might be relevant for all NSIS plug-in's that deal with COM interfaces (and the Shell), you might want to have a look here:
Theresias#
(As requested in the NSIS WIKI, I'm using this topic for feedback on StdUtils.)

LoRd_MuldeR, any plans to add a x86/x64 check to StdUtils? I am currently using...

      System::Call "kernel32::GetCurrentProcess() i .s"
System::Call "kernel32::IsWow64Process(i s, *i .r0)"
...but maybe there is a cleaner way to do this?
LoRd_MuldeR#
NSIS has that built-in already 🙂

!include "LogicLib.nsh"
!include "x64.nsh"

${If} ${RunningX64}
MessageBox MB_OK "We are running on x64!"
${EndIf}
Anders#
Originally Posted by Theresias View Post
The system::call code is still the same behind the scenes 😉
r2du-soft#
ShellExecAsUser not work in nsis unicode

hi

i use from ShellExecAsUser plugin for open the exe files run as user

Plugin:



when i use the nsis ansi then ShellExecAsUser plugin works correctly and exe file opened.

Section
ShellExecAsUser::ShellExecAsUser "open" "C:\1.exe"
SectionEnd
but if use from the nsis unicode:

[B]Unicode true
[/B]
Section
ShellExecAsUser::ShellExecAsUser "open" "C:\1.exe"
SectionEnd

plugin unable to open file and show message:

Anders#
There is no Unicode version of that plug-in. Try contacting the author.

Edit: A Unicode version has now been added to the wiki by the author.
BerndS#
Hi
Does anybody know a method that I can force the main NSIS Process to wait for the ShellExecAsUser process to end before it is possible to do anything else?


Regards
Bernd
Anders#
Originally Posted by BerndS View Post
Does anybody know a method that I can force the main NSIS Process to wait for the ShellExecAsUser process to end before it is possible to do anything else?
No I don't believe that is possible. The COM interface used to ShellExecute does not support waiting. You need ShellExecuteEx to wait, and even then, it would not work because the wait handle is in the wrong process.

Why do you need to wait for a "as user" process?
BerndS#
Hi
It is not essential to wait for the user process but it would feel better ;-)

I start a user process that does some downloads and configuration stuff when the main part of the installer is done. As I can click the "next" buttons in the NSIS part I can end the installer but the "user" part is not finished and is working ... this just does not look very nice.

Regards
Bernd
Anders#
Originally Posted by BerndS View Post

I start a user process that does some downloads and configuration stuff when the main part of the installer is done.
Assuming this is a "RequestExecutionLevel Admin + HKLM + $ProgramFiles" installer. These are multi-user installers and any per-user initialization should happen the first time a user runs the applications from the start menu. In a extreme case; someone could use fast user switching and start the application as a 3rd user (not the administrator and not the "user") before your call to ShellExecAsUser has completed.