- NSIS Discussion
- CRCCheck Failure with uiAccess
Archive: CRCCheck Failure with uiAccess
JasSays
6th May 2011 10:18 UTC
CRCCheck Failure with uiAccess
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".
Afrow UK
6th May 2011 14:09 UTC
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
JasSays
6th May 2011 14:55 UTC
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?
Anders
6th May 2011 16:15 UTC
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.
JasSays
6th May 2011 17:19 UTC
Originally posted by Anders
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.
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.
Afrow UK
6th May 2011 17:30 UTC
Originally posted by Anders
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?
Edit: @JasSays if it doesn't create a window, why are you using nsExec? Have you tried ExecWait? ExecShell (ShellExecute) cannot wait.
Stu
JasSays
6th May 2011 17:58 UTC
Originally posted by Afrow UK
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?
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:
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:
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);
}
}
}
This appears to work and is providing the correct results. However I would love there to be a way without using another process.
Afrow UK
6th May 2011 18:11 UTC
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
JasSays
6th May 2011 18:29 UTC
Originally posted by Afrow UK
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
Thanks for your reply, that's exactly what I wanted. :up:
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.
JasSays
7th May 2011 06:14 UTC
Originally posted by Anders
http://nsis.sourceforge.net/ShellExecWait
Thank you! That solved my problem and works perfectly.