Asked  7 Months ago    Answers:  5   Viewed   35 times

Windows Installer technology supports administrative installation. The command line for initiating administrative installation is: 'msiexec /a setup.msi'. I want to understand the purpose of this type of installation and in what scenarios are they helpful?



In the real world, it doesn't have all that much value at all. MSI was designed back in a day when a computer typically had a 2-20gb hard drive. They came up with all these "run from source" advertisement scenarios which seemed really cool back then but never really caught on in the real world.

Today, what /a does for me, a setup developer, is give me an easy way to "extract" an MSI and verify its contents. That's about it.

Tuesday, June 1, 2021
answered 7 Months ago

I find that wix is a great choice (in spite of the very very steep learning curve) if you need to manage installers in a complex environment because

  • setup definitions are stored in an XML format
  • it gives you full control to the underlying windows installer technology; the XML schema typically closely follows the windows installer database schema (which is also the main reason why the learning curve is so steep)
  • It is easy to integrate into your automated build
  • Parts of the setup can be generated automatically
  • It allows you to define small reusable modules and manage complex dependencies between them.
  • no cost or licensing issues (before wix we all had to use a single "Installshield PC")

Why the XML format is an advantage: this allows you to fully leverage code versioning systems like subversion or mercurial. Reviewing changes, examining history or even merging changes across branches is a breeze. Compare that to installshield projects which are opaque binary blobs.

What I mean by managing complex dependencies: in our case we have a big pool of reusable component libraries with a complex set of dependencies between them, and many applications that were build on top of that. Before wix, this was a nightmare when a new dependency was introduced somewhere: ALL setups had to be updated.

Now with wix, we have a ComponentGroup for each library, organized into a couple wixlibs. Each component group references other component groups that it depends on with a ComponentGroupRef. Application setup developers only need to reference the component groups of direct dependencies, and wix will do the rest by following the references. As a result, introducing a new dependency only requires making a single local change. Our automated builds and wix do the rest to regenerate all the setups.

Monday, August 2, 2021
answered 4 Months ago

What he's doing:

He's acquring some character array that he knows is the right length (such as the uppercase version of the String) and putting it as the backing array of the String. (The backing array is called value inside the String class.)

Why he's doing it:

To illustrate that you could put any char array there you wanted.

Why this is useful:

String is immutable, and this allows you to circumvent the immutability. Of course, this is not recommended to do - EVER. On the contrary, I would not be surprised if he was saying "Watch out, because people could potentially do this to YOUR code. Even if you think your stuff is safe, it might not be!"

The implications of this are wide reaching. Immutable variables are no longer immutable. Final variables are no longer final. Thread safe objects are no longer thread safe. Contracts you thought you could rely upon, you can no longer do so. All because some engineer somewhere had a problem he couldn't fix with normal means, so he delves into reflection to solve it. Don't be 'that guy'.

You'll also note that how the hashCode for that String would now be changed. So, if you've never calculated the hashCode for that String, it's still 0 so you're okay. On the other hand, if you have calculated it, when you go to put it in a HashMap or HashSet, it won't be retrieved.

Consider the following:

import java.util.*;
import java.lang.reflect.*;

class HashTest {        

    /** Results:
     C:Documents and SettingsglowcoderMy Documents>java HashTest
        Orig hash: -804322678
        New value: STACKOVERFLOW
        Contains orig: true
        Contains copy: false

    public static void main(String[] args) throws Exception {
        Set<String> set = new HashSet<String>();
        String str = "StackOverflow";
        System.out.println("Orig hash: " + str.hashCode());
        Field stringValue = String.class.getDeclaredField("value");
        stringValue.set(str, str.toUpperCase().toCharArray()); // 
        System.out.println("New value: " + str);
        String copy = new String(str); // force a copy
        System.out.println("Contains orig: " + set.contains(str));
        System.out.println("Contains copy: " + set.contains(copy));

I would bet he is doing this as a warning against bad behavior rather than showing a 'cool' trick.

EDIT: I found the article you're referring to, and the article it is based on. The original article states: "This means that if a class in another package "fiddles" with an interned String, it can cause havoc in your program. Is this a good thing? (You don't need to answer ;-) " I think that makes it quite clear this is more of a protection guide than advice on how to code.

So if you walk away from this thread with only one piece of information, it is that reflection is dangerous, unreliable, and not to be trifled with!

Wednesday, August 18, 2021
answered 4 Months ago
  1. Use one component per file and set each file to be keyfile in its own component. This avoid all sorts of component referencing and file replacement issues. Be aware that multi-file assemblies must share the same component as they are intended as one "atomic" file system unit.
  2. In addition you must also increment the version number for each build or set REINSTALLMODE to emus instead of the default omus. Never use amus.
  3. My advice: go with the file version updates - it is much more reliable. Like you state the File Version is used, it must be incremented. I like to auto increment the build version number (last digit). It has been a while, but I think you just replace the number with * and it auto increments. I think you can do this from the Visual Studio project property view.
  4. Maybe read up on the file versioning rules as well. Essentially versioned files are version compared, and for unversioned files the create and modify date stamps are compared and the file is replaced if it is unchanged on disk. More sample info.
  5. Remove the "always overwrite" flag you enabled for all the files you enabled it for. This flag may work poorly with patches if you ever need them and also with other features.
  6. When a major upgrade creates two side-by-side installations it hasn't worked. What you are left with are two different products installed at the same time. There is good inline help in Installshield itself with regards to how a major upgrade is set up. Which version of Installshield are you using? The version bundled with Visual Studio may not feature this help material.

A note on major upgrades and "reverted files":

A warning on a classic major upgrade issue: be aware that changed, unversioned files not set to be permanent on original install may be uninstalled during a major upgrade and then reinstalled yielding the impression that they have been replaced, but they are actually deleted and recreated. These are typically important settings files like XML files or similar - and people struggle with this issue a lot. Major upgrades are essentially a sequence. The old product is uninstalled, and then the new one is installed or vice versa. In the former case the files may be uninstalled first and then recreated. This does not happen in the latter case if component referencing is done right because the files that are matching between products are not uninstalled, but retained and then overwritten if need be (according to the file replacement / versioning rules).

Monday, October 4, 2021
Kevin S.
answered 2 Months ago

To sum up what's in the comments, theoretically this is redundant. Deferred execution is irrelevant in this case. At the point of yield full execution has already been made: contents of bucket are already calculated and there is nothing to defer.

There is also no problem caused by the iterator block behaviour - each time we're back in this implementation the bucket is being reset and recreated (bucket = null immediately after yield). Even if someone would cast the result to the array type and modify it, we don't care.

An advantage of this approach seems to be only elegance: there is a type consistency between all calls to resultSelector. Without the "redundant" Select, the actual type would have been TSource[] most of the time, and IEnumerable<TSource> for the trailing elements that did not fill the whole bucket.

However, one can imagine the following scenario:

  1. someone using this function notices that the actual type is an array
  2. because of some urge need to improve performance, they cast the received batch to TSource[] (e.g. they can now skip elements more efficiently, as Skip is not optimized for arrays)
  3. they use the method without any problems, because it happens that Count() % size == 0 in their case

Until, later, it happens that one additional elements pops in, causing the last yield to be executed. And now the cast to TSource[] will fail.

So, depending on the number of elements and size the method would behave inconsistently with regard to its result type (passed to the given callback). One can imagine other elaborate scenarios where this inconsistency can cause trouble, like some ORM that, depending on the actual type, serializes objects into different tables. In this context pieces of data would end up in different tables.

These scenarios are of course all based on some other mistake being made, and do not prove that without the Select the implementation is wrong. It is however more friendly with the Select, in a sense, that it reduces the number of such unfortunate scenarios to a minimum.

Thursday, November 4, 2021
answered 1 Month ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :