WiX behaving badly on XP machine with windows update issues - wix

My WiX bundle behaves very badly on a specific XP machine (x86). It stalls for six minutes during the "initializing" phase (before any bundled installers are run). From the logs it seems extremely likely it is due to the dodgy state of windows update on the machine:
[090C:0FC0][2018-03-27T19:31:17]i358: Pausing automatic updates.
[090C:0FC0][2018-03-27T19:37:23]w308: Automatic updates could not be paused due to error: 0x80080005. Continuing...
[090C:0FC0][2018-03-27T19:37:23]i360: Creating a system restore point.
I am using WiX v3.10 to make the bundle. I can find very similar situations from google search but the solution always revolves around updating the target machine. I need this installer to work as expected regardless. When I test a regular msi on the same machine it goes through fine.
Is there any way I can mitigate this issue? E.g. can I stop the WiX bundle from trying to pause windows update or something similar? The fact that the installer doesn't even notify what the issue is is extremely problematic, any user is likely to be confused.
The whole point of this WiX installer is to make an install package portable and simple but this actually seems LESS portable than just the msi...
Update: Also tried building the bundle with WiX 3.11 but got same problem. Though now it produces an actual error rather than installing regardless, which I suppose is an improvement.

UPDATE: after looking in the WiX source code it looks like WiX's Burn feature is making a few calls to Microsoft.Update.AutoUpdate (%SystemRoot%\System32\usoapi.dll - %SystemRoot%\SysWOW64\wuapi.dll) and a few other COM objects here and there.
See towards the bottom (screenshot) for a hot COM tip to quickly get an overview of different COM object models.
It must be this AutoUpdate call which hangs causing a timout along the lines of what is described in this blog. I believe you can find the exact source code location by searching for hr = WuaPauseAutomaticUpdates(); in the elevation.cpp WiX Burn source file (Github link). The actual calls to the COM object are in wuautil.cpp.
I am not familiar with the Windows Update Agent Object Model, but I suppose you could try to call the Pause function in a test VBScript just to see what kind of error you get on your problem system (if any). I can't see how you would get anything but a lockup on your problem system, so maybe try first on your main box? This is obviously at your own risk. I would assume a reboot or a call to Resume will continue the process as normal. I also see a call to SystemInformation.RebootRequired in the C++ code, which I have also added to the VBScript:
Set autoupdate = CreateObject("Microsoft.Update.AutoUpdate")
autoupdate.Pause()
MsgBox Err.Number & " " & Err.Description
Set sys = CreateObject("Microsoft.Update.SystemInfo")
MsgBox sys.RebootRequired
' autoupdate.Resume() ' Enable to resume AutoUpdate
Set sys = Nothing
Set autoupdate = Nothing
Let's face it: Windows Update is broken on your XP machine - isn't it? Maybe the WiX guys can add a shorter timeout? I am not sure what is better - 1) to shorten the timeout, 2) to remove the whole call or 3) to just bomb out telling the user that Windows Update is broken? Frankly the latter would probably alert the user to something very serious (often malware).
UPDATE: as you state yourself, Windows Update is almost certainly broken on this particular machine. I would try the MSI properties suggested below for testing, and then zap Windows Update as suggested here (same link as below) (techical).
But wait, maybe a malware check is in order, before wasting time on anything else?
Maybe try this free Sysinternals tool? Checks all running processes by hash using almost 70 scanning engines (no heuristics though). Fire up all you got (only running processes are checked)
Go File => Show Details for All Processes and then elevate to get to scan system processes as well. Now click "System" to scan drivers for example (*.sys files).
Often a great way to get your system admin to agree to rebuild a problematic machine for everyone. Suddenly you go from "deployment problem" to "machine specific problem" - and it is out of your hair. GIGO problem.
Nicely formatted and phrased question BTW. And just for reference: Sysinternals.
Workaround?
I have never seen this, but I have seen some MSI files suddenly pausing for a long time whilst installing whereas they would install quickly during test installs just minutes before.
My guess is that this could be related to system restore and the creation of a restore point at certain "intervals". I am not sure what algorithm is used to determine when such a restore point is created and not, but I wrote an answer many years ago on the issue of speeding up MSI installations: How can I speed up MSI package install and uninstall?
As you will see, you can disable the creation of a restore point for your setup by setting an appropriate command line involving the property MSIFASTINSTALL (and a few other tweaks - please just read the linked serverfault.com answer). I would try this to see if your setup stops locking up / hanging.
Causes?
Some hits from the web:
Could it be that Windows Updates is also trying to create a restore point at the same time as your MSI-package? Setup hang when trying to disable windows updates (PhilDW)
Could it be that the Windows Update feature is corrupted?
Similar issue: WiX Toolset installs VC++ redistributable (x86) 2015 too slowly
I would first try the MSI properties mentioned as a "workaround" above, and if that doesn't work, I would try to see if fixing Windows Update as explained in the link directly above works. Crucially I would also let Windows Update complete its task of installing all available updates before running your bundle again.
Hot Tip (COM)
I don't like to recommend commercial tools, but we all need some quick tricks and quick wins at times - which is what this is about. Get hold of VbsEdit and use its light weight object browser to quickly see details from any COM object model. Just do a CreateObject and you will instantly see the object model in the object browser to the right in the application window (View => Object Browser if it is not there).
Just type in something like this:
Set installer = CreateObject("WindowsInstaller.Installer")
I find this to be a time-saver when I need to deal with legacy COM stuff and Visual Studio is very sluggish. I just have the VbsEdit trial version, and it allows basic editing. And let's throw in a rant: why on earth do they not make a Javascript version? I am missing something - as usual :-).
Throwing in a second screen shot to show a more interesting object model information tidbit:
Should you want to try it, here are some other CreateObject statements you can try:
Set autoupdate = CreateObject("Microsoft.Update.AutoUpdate")
Set fso = CreateObject("Scripting.FileSystemObject")
Set scriptshell = CreateObject ("WScript.Shell")
Set dictionary = CreateObject("Scripting.Dictionary")
Set shell = CreateObject("Shell.Application")

Related

WIX Installer: Prevent installation on Windows Server 2012 R2

I have a WIX project that must only be installed on Windows Server 2016 (or newer).
Looking at Microsoft documentation, VersionNT for:
Windows Server 2016 is 603,
Windows Server 2012 is 602.
The VersionNT for Windows Server 2012R2 has never been mentioned.
When I use below line of code:
<Condition Message="!(loc.RequireServer2016)"><![CDATA[INSTALLED OR (VersionNT >= 603)]]></Condition>
it still lets me install on Windows Server 2012R2.
How can I limit the installation of my software to only Server 2016 and prevent it from installing on Server 2012R2?
INSTALLED should be Installed. Properties are case sensitive and you must definitely fix that in your condition - or else that part of the condition will never be true - even if the product is installed.
The rest of the condition looks OK actually. Just some ideas to determine what is wrong:
WiX Source Element: Are you sure you have included this condition in the right location in the WiX source?
I would put it directly under the Product element. The proof is in the compiled MSI file. Look if there are entries in the LaunchCondition table.
I assume you have Orca to check with, otherwise use one of the other, free MSI viewers (towards bottom): How can I compare the content of two (or more) MSI files?
Versionlessness: There have been massive changes to how the OS version is detected in Windows 10. I don't know if this also affects Windows Server 2012R2 as well.
It seems the overall idea is that Windows is now "evergreen versionless" (how is that for a term) - meaning that VersionNT does not necessarily report the correct version of the OS at all!
Please read this answer rather than me repeating things here: Windows 10 not detecting on installshield.
In order to determine what the value of VersionNT really is in your setup, I'd use one of two ways to check properties at runtime. The latter option (logging) is generally quicker and easier, whereas the first option allows you to also evaluate complex conditions as the setup runs and show whether they are true or false at runtime by using the Session.EvaluateCondition method (I use this method call when conditions are complex and confusing and I want some runtime proof that they behave like I expect):
Property Debugger VBScript: I have a property debugger VBScript I use to display a bunch of property values at runtime for an MSI file and to evaluate conditions at runtime to show whether they evaluate to true or not - as stated above. If I were you I would use such a script to display VersionNT at runtime (and whatever other property or condition you want to check).
It is recommended that you don't use VBScript for production setups - debugging only. Rob is the WiX creator - I agree with all his anti-script arguments, but personally still conclude that VBScript is useful for debugging - quick, easy & embedded source with no compilation. Setting up a whole compiled custom action just to retrieve a few properties for testing is overly time consuming (debugging would be better though and easier with "real code" such as C++).
In corporate environments VBScript has seen lots of use because of the embedded source - you can always find the real custom action source embedded in the MSI - not so with compiled custom actions where the source you compiled from could be unavailable (due to the inherent chaos of all things technical - in the real world) - which is very bad indeed.
Another benefit is the simplicity of VBScripts and how corporate application packagers master the complexity better than C++ / C#. But overall script custom actions always cause problems along the lines of what Rob mentions (anti-virus blocking, poor debugging and lackluster coding without proper error handling).
Crucially you will have control of security software / anti virus in corporate deployment scenarios. You can deal with problems in a logical way and tweak things until the package deploys reliably.
Finally corporate desktops are SOEs - standardized platforms with much less variability than regular PCs (which can be in a much greater diversity of states and hence see more deployment problems).
The real problem is basically custom actions altogether, they are very error prone: Why is it a good idea to limit the use of custom actions in my WiX / MSI setups? A lot more information than you need I guess. The moral of the story for me is: use whatever gets the job done quickest, but don't think scripts are good enough for production code for world-wide distribution.
For corporate deployment one should eliminate ad-hoc script custom actions in favor of well-tested C++ custom actions with full rollback support driven by custom MSI tables which yields full declaration of what should happen during the install.
Logging: Just create a log file for the setup and check the value of VersionNT in it. I like to enable logging for all setups as explained here: installsite.org on how to do logging - see the "Globally for all setups on a machine"-section). Despite the performance hit, I always have a log file ready in the TEMP folder for debugging. The same link will show you how to make an ad-hoc log for a single install only as well (essentially: msiexec.exe /i "c:\filename.msi" /QN /L*V "C:\msilog.log" REBOOT=R - silent install with logging and suppressed reboot - even more logging info).
Property Debugger Demo: This is beyond what you asked, but I think you may struggle to debug this issue and similar ones for your server deployments, and I want to give you a quick demo on how to evaluate MSI conditions in VBScript.
Your condition above is generally too simple to bother with this, but this is a general approach for very complicated conditions - for example when you want to run a custom action only on repair or on major upgrade initiated uninstalls - the proof is always in testing, no matter how hard you think about things.
Your condition evaluated at runtime using VBScript:
MsgBox "Condition: " & CBool( Session.EvaluateCondition("Installed OR (VersionNT >= 603)"))
Such a VBScript custom action can be inserted in different sequences and in different locations as you wish. Property values may differ depending on your sequencing (!) and also what installation mode you are in (install, uninstall, repair, modify, self-repair, major upgrade (involves one MSI being installed and one being uninstalled), minor upgrade, minor upgrade patch, major upgrade patchetc...) and whether you are running in deferred or immediate context or whether you are running silently or interactively, and whatever variable I have forgotten - lots of moving parts in MSI. For example if you insert the custom action at the beginning of the UI sequence, then AppSearch has not run yet, and some properties are not yet set. You can also insert property debugging constructs in the administrative- and advertisement-installation sequences if need be.
And maybe a couple of further conditions for testing purposes:
"NOT Installed AND NOT WIX_UPGRADE_DETECTED"
"NOT Installed AND NOT REMOVE~="ALL""
And then some that warrant testing due to complexity (not my conditions, they are from here):
Installed AND (NOT REMOVE="ALL" OR UPGRADINGPRODUCTCODE)
NOT Installed OR Installed AND (NOT REMOVE="ALL" OR UPGRADINGPRODUCTCODE)
I hope that was a clear concept. I have a VBScript for such property debugging, but it is too large and messy to put here.
In light of this article about the values of VersionNT values for Windows 10 and Server 2016:
https://support.microsoft.com/en-us/help/3202260/versionnt-value-for-windows-10-and-windows-server-2016
I would start with a condition of:
VersionNT=603 and MsiNTProductType > 1
where the latter indicates a server system:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa370329(v=vs.85).aspx
Beyond that, look at the WindowsBuild property to see if it has a useful value for Server 2016 (or a value you can use to exclude Server 2012). You could also look at a custom action that calls GetSystemMetrics:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724385(v=vs.85).aspx
to see if SM_SERVERR2 is set in 2012.
You do not need a condition that includes the Installed property. When you first do the install the Installed value is not set. If you try to install the same MSI again you won't get as far as the launch condition because Windows will see that this particular ProductCode is already installed and go into maintenance mode (repair, uninstall, feature change type stuff). So it's not clear why you think you need it. If you need to be sure that launch conditions apply only on the initial install the add the condition "Not Installed" to the LaunchConditions action in the UI and execute sequences.

Disable repair mode and upgrades in wix installer

We have a unique requirement to create an msi using wix,the catch is that the msi must support multiple instance installation. User should be able to use the msi to install the product more than once on a particular system, so in order to achieve this we should disable repair mode and upgrades in msi, so literally each invocation of msi should be treated as fresh install.
Is the above requirement technically feasible with Wix? I am aware that having unique product code and package code for every invocation of msi will treat the installation as fresh install. Can this be achieved using a wrapper around the msi?
You could do this with a wrapper around the MSI. In general your wrapper program would start with the base MSI, alter the ProductCode and PackageCode using the Windows Installer APIs, copy this MSI to a location on the system then install it from there.
I say "copy and install" because it's futile trying to disable repair - it's too baked into the architecture of Windows Installer. If you have each separate MSI product cached somewhere then repair will work using that unique MSI, and it also means that you could modify as well. Repair is too unpredictable to completely prevent. Any shared files can trigger repair from other installed products that share them. What do clients do if they accidentally delete files or registry entries? And there's this about keeping the source MSI available, although the list of reasons doesn't come with a lot of explanation, Rule 31:
https://blogs.msdn.microsoft.com/windows_installer_team/2006/05/24/tao-of-the-windows-installer-part-3/
There are a lot of other issue that aren't mentioned, so it's not clear if you care about patches and maintenance in general, about multiple entries in Programs/Features (that you could suppress, but how do you uninstall?) and so on. It's also not clear that each of these separate installs don't conflict with each other in any way, such as common files/registry entries, service names, files being installed in the same location with the same name.
Before sending you to the MSI SDK I should add that I dislike this instance transform concept myself, and have not used it in practice. It might be that I have become a grumpy old man! :-).
MSINEWINSTANCE: Please investigate the MSINEWINSTANCE property and read up on the MSI SDK topic: "Installing Multiple Instances of Products and Patches". And here is perhaps a better example - more practically oriented.
Also some context on why I am not too keen on this feature. Carolyn Napier was on the original MSI team - this is straight from the horse's mouth as they say.
I know some people claim success with these instance transforms (Chris Painter might be able to illuminate my claims here), but I'd rather virtualize in scenarios such as these. Please see this age-old post from serverfault.com: I want to install an MSI twice (please skim all the other answers in that "thread" too).
APP-V: I have almost zero App-V experience, but my guess is that this is what you should try to convince your manager to spend some time on investigating. Maybe call in some favors and talk to guys who are operative in current deployment. They always have the current prevailing prejudice to report - with the tricks that make things work in the real world.
Great if you can let us know how you end up solving the problem.
Disable Repair & Modify: And for the record: disabling repair and modify (buttons only) can be done by setting the ARPNOMODIFY and ARPNOREPAIR properties. But this is not what you are looking for to allow multiple instance installations. MSI is not easily fooled and knows what you have installed and when - no reason to waste time testing these "options". All these two properties do is to hide or disable the modify and repair buttons - yields nothing you need apart from that.

Uncaught Error: ENOENT: no such file or directory, open 'C:\tmp\statistics.ivr'

Description of the problem:
I'm testing the irisVR Beta and I'm trying to launch some cranium.obj 3D model I have. I dragged and dropped the model directly on irisVR launch window and clicked launch. A terminal opens up for half a second and closes. Then nothing happens.
Image 1 -- Iris launch window -- indefinite progress bar
Image 2 -- irisVR console.log
Here is the error I am getting in the console.log:
Question:
What is causing this error, and how do I fix it?
Nate here from IrisVR. Just wanted to let you know that for the next few versions (next few weeks), we have removed OBJ support. Your question makes me realize that our documentation needs some TLC and is misleading - I have added updating it to my task list and it should be amended by EOD tomorrow. Thanks for that!
You'll notice that the drop-zone graphic only includes the SketchUp and Revit icons. This won't last long, I promise! We are building a new system for handling the model geometry and optimizing it for VR and it broke part of the OBJ code. Ultimately, these changes are going to lead to some terrific improvements. Given our limited programming bandwidth right now, we had to pick two file formats to carefully maintain throughout this migration process and we'll pick up the pieces with OBJ ASAP
Thanks again for your patience and for using the app! In the meantime, give a SketchUp model a try :)
Another tester here - ran into the same issue on a fresh Bootcamp install, it's not isolated to the *.obj support that Nate mentioned as was able to recreate with both Sketchup and Revit models.
The current release (v0.2.4) appears to have some dependencies on the Microsoft Visual C++ 2010 redistributable. If you don't have this installed, it will block the associated IrisVR ModelConverter from running and that statistics.ivr file from being generated. Unfortunately there is nothing logged to this effect, so took a bit of digging to find. You will however see a window flash up briefly, then close. This is the ModelConverter attempting to launch and quit.
To resolve, download and install the redistributable from here.

Can't eliminate Access corruption

My firm's Access database has been having some serious problems recently. The errors we're getting seem like they indicate corruption -- here are the most common:
Error accessing file. Network connection may have been lost.
There was an error compiling this function.
No error, Access just crashes completely.
I've noticed that these errors only happen with a compiled database. If I decompile it, it works fine. If I take an uncompiled database and compile it, it works fine -- until the next time I try to open it. It appears that compiling the database into a .ACCDE file solves the problem, which is what I've been doing, but one person has reported that the issue returned for her, which has me very nervous.
I've tried exporting all of the objects in the database to text, starting with a brand new database, and importing them all again, but that doesn't solve the problem. Once I import all of the objects into the clean database, the problem comes back.
One last point that seems be related, but I don't understand how. The problem started right around the time that I added some class modules to the database. These class modules use the VBA Implements keyword, in an effort to clean up my code by introducing some polymorphism. I don't know why this would cause the problem, but the timing seems to indicate a relationship.
I've been searching for an explanation, but haven't found one yet. Does anyone have any suggestions?
EDIT: The database includes a few references in addition to the standard ones:
Microsoft ActiveX Data Objects 2.8
Microsoft Office 12.0
Microsoft Scripting Runtime
Microsoft VBScript Regular Expressions 5.5
Some of the things I do and use when debugging Access:
Test my app in a number of VM. You can use HyperV on Win8, VMWare or VirtualBox to set up various controlled test environments, like testing on WinXP, Win7, Win8, 32bit or 64 bits, just anything that matches the range of OS and bitness of your users.
I use vbWatchDog, a clever utility that only adds a few classes to your application (no external dependency) and allows you to trap errors at high level, and show you exactly where they happen. This is invaluable to catch and record strange errors, especially in the field.
If the issue appears isolated to one or a few users only, I would try to find out what is special about their config. If nothing seems out of place, I would completely unsintall all Office component and re-install it after scrubbing the registry for dangling keys and removing all traces of folders from the old install.
If your users do not need a complete version of Access, just use the free Access Runtime on their machine.
Make sure that you are using consistent versions of Access throughout: if you are using Access 2007, make sure your dev machine is also using that version and that all other users are also only using that version and that no components from Access 2010/2013 are present.
Try to ascertain if the crash is always happening around the same user-actions. I use a simple log file that I write to when a debugging flag is set. The log file is a simple text file that I open/write to/close everytime I log something (I don't keep it open to make sure the data is flushed to the file, otherwise when Access crashes, you may only have old data in the log file as the new one may still be in the buffer). Things I log are, for instance, sensitive function entry/exit, SQL queries that I execute from code, form open/close, etc.
As a generality, make sure your app compiles without issue (I mean when doing Debug > Compile from the IDE). Any issue at this stage must be solved.
Make absolutely sure you close all open recordsets, preferrably followed by setting their variables to Nothing. VBA is not as sensitive as it used to be about dangling references, but I found it good practice, especially when you cannot be absolutely sure that these references will be freed (especially when doing stuff at Module-level or Class-level for instance, where the scope may be longer-lived than expected).
Similarly, make sure you properly destroy any COM object you create in your classes (and subs/functions. The Class_Terminate destructor must explicitly clean up all. This is also valid when closing forms if you created COM objects (you mentioned using ADOX, scripting objects and regex). In general keeping track of created objects is paramount: make sure you explicitly free all your objects by resetting them (for instance using RemoveAll on a dictionary, then assigning their reference to Nothing.
Do not over-use On Error Resume or On Error Goto. I almost never use these except when absolutely necessary to recover from otherwise undetectable errors. Using these error trapping constructs can hide a lot of errors that would otherwise show you that something is wrong with your code. I prefer to program defensively than having to handle exceptions.
For testing, disable your error trapping to see if it isn't hiding the cause of your crashes.
Make sure that the front-end is local to the user machine, You mention they get their individual front-end from the network but I'm not sure if they run it from there or if it it copied on their local machine. At any rate, it should be local not on a remote folder.
You mention using SQL Server as a backend. Try to trace all the queries being executed. It's possible that the issue comes from communication with SQL Server, a corrupt driver, a security issue that prevents some queries from being run, a query returning unexpected data, etc. Watch the log files and event log on the server closely for strange errors, especially if they involve security.
Speaking of event log, look for the trace of the crash in the event log of your users. There may be information there, however cryptic.
If you use custom ribbon actions, make sure thy are not causing issues. I had strange problems over time with the ribbon. Log all all function calls made by the ribbon.

What causes difference in VB6 app testing result when running from Dev machine vs installed?

I'm new to VB6 but i'm currently in charge of maintaining a horror of editor like tool with plenty of forms, classes, modules and 3rd party tools all chunk together like the skin faces on that guy in the texas chainsaw massacre...
What i don't understand is why i get different results when i run the app in debugging mode, vs when i compiled it and run it on my devevelopment pc vs when i installed it on a different pc.
Yes i know i'm dumb, so please direct me to where i can find out more about this. I'm hoping to find out something like different linking, registry related etc connection that i'm simply not getting right now, i.e. something like wax on, wax off :P
The main pain in the neck is when i'm trying to debug some errors from my QA and i need to find a spare pc to test this on plus i can't directly debug because i don't know where the code is if i do it that manner.
Thanks.
i run the app in debugging mode vs when i compiled it and run it on my
devevelopment pc
When you compile you have the option of compiling to native code or pcode. The debugger runs using pcode only. Under rare circumstances when you compile to native code there will be a change in behavior. This particular is really rare. I used VB6 since it's release and I may get it once or twice a year. My application is a complex CAD/CAM creating shapes and running metal cutting machine and has two dozen DLLs. Not a typical situation. At home with my hobby software I never ran into this problem.
There are another class of errors that result from event sequencing problems. While VB6 isn't truly multi-tasking it has the ability to jump out of the current code block to process a event. If it re-enters the same block for the new event interesting things (to say the least) can result. I think this is the likely source of your problems as you software is an editor which is a highly interactive type of software.
In general the problem is fixed by reordering the effected areas. You find the effected area by inserting MsgBox or write to a text file to log where you are. I recommend logging to a text file as MsgBox tend to alter behavior that are timing or multi-tasking related.
Remember if a event fire while VB6 in the middle of a code block and there a DoEvents floating around then it will leave the code block process the event and return to the original code block. If it re-enters the same code block and you didn't mean for this to happen then you will have problems. And you will have different problems on different computers as the timing will be different for each.
The easiest way to deal with this type of issues is create some flag variables. In multi-tasking parlance they are known as semaphores or mutexes. WHen you enter a critical section of code, you set it true. When you leave the routine you set it to false. If it is already true when you enter that section of code you don't execute it.
when i installed it on a different pc.
These are usually the result of the wrong DLL installed. Most likely you have an older version while the target has a newer version. I would download the free Virtual PC and create a clean Window XP install to double check this.
If your problem is event timing this too can be different on different computers. This is found by logging (not MsgBox) suspect regions.
If you can display a screen shot or the text of your specific errors then I can help better.
The first thing to check would be the versions of all the dlls that your app depends on - including the service pack version of the VB6 dll.
Have you any more specific details about what's behaving differently?