In my NSIS install, my application is ran a few times, during update to check various processes, look for a mutex, and while uninstalling for the same and for cleanup. The problem is, my application is an accessibility application with uiAccess="true" in the manifest. This is a requirement and cannot be changed. The problem is, NSIS fails to run my application due to this, I have changed the installer to use uiAccess and digitally signed the install however this causes a CRC check failure:
"Install integrity check has failed. Common causes include incomplete download and damaged media. Contact the installer's author to obtain a new copy."
I have also turned off CRCCheck:
CRCCheck off
Which appears to have no effect, any thoughts? Am I going about this the wrong way? Is there another way to launch accessibility applications? With uiAccess="true" my application fails to even start at the end of install.
Edit:
I noticed that using nsExec::Exec returns "error", is there any way to find out what error exactly is received? The file exists and runs like normal if uiAccess="false".
CRCCheck Failure with uiAccess
11 posts
Try with ExecDos. Its exit code has some defined values which correspond to the GetLastError API (you need to look at the source code).
Stu
Stu
Thanks for the reply, that got me an exit code: -14. Looking through the source of execDos, it looks like error ERR_CREATEPROC, I don't see it call GetLastError in there although my c++ is a bit rusty.
Edit: This got me thinking, in the source of ExecDos it looks like it redirects standard output. I've now wrote an application which takes command line arguments and redirects them to another process. It validates that the process and destination contain the same public keys for security and it is running with uiAccess=false. It can successfully query the app and return the exit code to NSIS.
NSIS:
nsExec::Exec '"$INSTDIR\Invoker.exe" -TARGET:"$INSTDIR\App.exe" -SOMEFLAGS'
Invoker then runs the TARGET with the specified flags and returns the exit code as it's own. I would rather use NSIS instead of this convoluted process however, any thoughts?
Edit: This got me thinking, in the source of ExecDos it looks like it redirects standard output. I've now wrote an application which takes command line arguments and redirects them to another process. It validates that the process and destination contain the same public keys for security and it is running with uiAccess=false. It can successfully query the app and return the exit code to NSIS.
NSIS:
nsExec::Exec '"$INSTDIR\Invoker.exe" -TARGET:"$INSTDIR\App.exe" -SOMEFLAGS'
Invoker then runs the TARGET with the specified flags and returns the exit code as it's own. I would rather use NSIS instead of this convoluted process however, any thoughts?
You must use ExecShell to start applications with Vista manifests...
Signing a NSIS installer is a bit hard, you can't just sign it after makensis has completed, it must happen during the build phase.
Signing a NSIS installer is a bit hard, you can't just sign it after makensis has completed, it must happen during the build phase.
Can ExecShell wait until the process has completed and return an exit code? I know it's not a coding limitation as my own implimentation outside of NSIS works. My application does not create a window and simply returns one of several exit codes as a query. Both the installer and uninstaller are signed.Originally Posted by Anders View PostYou must use ExecShell to start applications with Vista manifests...
Signing a NSIS installer is a bit hard, you can't just sign it after makensis has completed, it must happen during the build phase.
We've been signing after build has completed without any issues. Haven't disabled CRC check. What are the reasons for signing the exehead rather than the entire installer?Originally Posted by Anders View PostSigning a NSIS installer is a bit hard, you can't just sign it after makensis has completed, it must happen during the build phase.
Edit: @JasSays if it doesn't create a window, why are you using nsExec? Have you tried ExecWait? ExecShell (ShellExecute) cannot wait.
Stu
I've tried all the above and they all fail with either null exit code or a "error" result (except ExecShell, but that does not wait). I think it has to do with the application having a manifest with uiAccess="true" and that causes NSIS to fail to run it under all of NSIS' methods. Granted, needing ui access is rare so I'm not surprised no one else has ran into this. Now I'm using this method:Originally Posted by Afrow UK View PostWe've been signing after build has completed without any issues. Haven't disabled CRC check. What are the reasons for signing the exehead rather than the entire installer?
Edit: @JasSays if it doesn't create a window, why are you using nsExec? Have you tried ExecWait? ExecShell (ShellExecute) cannot wait.
Stu
NSIS installs application.exe with the following execution level:
<requestedExecutionLevel level="asInvoker" uiAccess="true" />
and invoker.exe which has this requested execution level:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Before installing, NSIS does this:
ExecWait '"$INSTDIR\invoker.exe" -TARGET:"$INSTDIR\application.exe" -FLAGS' $0
...
invoker.exe boots up application.exe with shell but also waits for it to complete:
This appears to work and is providing the correct results. However I would love there to be a way without using another process.
static void Main(string[] sargs)
{
.....
using (Process p = CreateProcess(targetApplication, true, [flag]))
{
WaitForProcess(p);
Environment.ExitCode = p.ExitCode;
}
.....
}
private static Process CreateProcess(string filename, bool showWindow, string arguments)
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.Arguments = arguments;
psi.FileName = filename;
psi.WorkingDirectory = Path.GetDirectoryName(filename);
psi.UseShellExecute = true;
if (!showWindow)
psi.WindowStyle = ProcessWindowStyle.Hidden;
return Process.Start(psi);
}
private static void WaitForProcess(Process p)
{
using (ManualResetEventSlim reset = new ManualResetEventSlim(false))
{
while (!p.HasExited)
{
reset.Wait(100);
}
}
}
You need to call ShellExecuteEx directly if you need to wait (sorry I should have said this earlier). This is what Process.Start (with UseShellExecute = true) uses underneath. You can call ShellExecuteEx with the System plug-in. The filled in SHELLEXECUTEINFO struct has a hProcess member which you can use WaitForSingleObject API on followed by GetExitCodeProcess.
Btw why are you using a ManualResetEventSlim in your .NET program? Why not just use Thread.Sleep(100) or simpler, use p.WaitFor Exit()?
Stu
Btw why are you using a ManualResetEventSlim in your .NET program? Why not just use Thread.Sleep(100) or simpler, use p.WaitFor Exit()?
Stu
Thanks for your reply, that's exactly what I wanted. 👍Originally Posted by Afrow UK View PostYou need to call ShellExecuteEx directly if you need to wait (sorry I should have said this earlier). This is what Process.Start (with UseShellExecute = true) uses underneath. You can call ShellExecuteEx with the System plug-in. The filled in SHELLEXECUTEINFO struct has a hProcess member which you can use WaitForSingleObject API on followed by GetExitCodeProcess.
Btw why are you using a ManualResetEventSlim in your .NET program? Why not just use Thread.Sleep(100) or simpler, use p.WaitFor Exit()?
Stu
Oh and the reason for the wait handle is there is other functionality that I have left out of the example, the ability to stop waiting, time out, and other functions. Some argue using a wait handle instead of Sleep is more predictable/consistant at the expense of resources. For me, I just like the added functionality. For the purpose of my example it is redundant.
Thank you! That solved my problem and works perfectly.Originally Posted by Anders View Post