views:

549

answers:

7

I have a Windows application (VS2005/C#) which comes in two versions, Enterprise and Pro. In the Pro version, some of the features and menus are disabled. Currently, I'm doing this by commenting out the disabling code to create the Enterprise version, then I copy each executable file to another location. Obviously this process is fraught with peril... :)

I would like to have two folders for my two executable files, and visual studio should put the code to disable the features in the pro version, and put each in their correct folders. I have installer projects that would pick up the files from there and make the installers for the two versions. That part is already working, but I'm manually copying the two executables into the right folders before I build the installers. So it sucks...

What I'd like to do is something like this:

#ifdef PROVERSION
part1.disable();
part2.disable();
#endif

Is this possible with Visual studio???

Note, my overall goal is to automate the process of creating the two installers.

A: 

Why not create a separate assembly that enables / disables the features as required? Then just include the appropriate assembly for a particular version...

moobaa
A: 

What type of licensing scheme are you using. I have done a few apps were the license key activated the feature sets so you really only had one executable.

Dan Blair
We are using Uniloc - but we are using a wrapper on the executable at the moment, because we don't have time to implement the license-checking features in code until the next release. Eventually this will be a non-issue because we will use the feature-management of the Uniloc system.
Jasmine
+1  A: 

you can create a new Conditional Compilation Constant and define PROVERSION

lomaxx
+2  A: 

Yes, thats certainly possible. A visual studio solution comes with two configuration by default. (Release and Debug). You can create additional ones like "EnterpriseDebug" and "EnterpriseRelease" Just go to the Configuration Manager under (Build | Configuration Manager ) and then select <New...>

The configuration manager will by default create a folder named after the configuration and place the compiled binary files into it. You will have to manually set the conditional compilation symbols and use (#if) statement to add/remove your features.

Matt Brunell
+2  A: 

from the BUILD menu, select configuration manager option

on the active solution configuration dropdown select "new"

create two new 'configurations' one for PRO and one for ENTERPRISE

close the configuration manager.

open the project properties (from the project context menu) select the build tab

select the PRO configuration (from the CONFIGURATION dropdown)

enter your compilation constant "PROVERSION" into the conditional compilation symbols textbox.

now all you have to do is select the config you want to build from the config dropdown on the main toolbar and then do your build.

when you build the PRO using the PRO configuration the compiler pragmas (#IF PROVERSION) scattered throughout your code will include the code limiting your feature set.

you may also consider setting a ENTERPRISE constant for the ENTERPRISE configuration if you want to specifically include ENTERPRISE features in an ENTERPRISE build (versus disabling enterprise features in a PRO build)

This is exactly what I tried to do at one point, but I couldn't get it to work. Sorry I forgot to mention that, but it's why I used "Configurations" in the title. I will try again though. This is exactly what I want it to do - put each file in correct folder, the encrypter can pick up from there.
Jasmine
This worked very nicely BTW, once I finally got my configurations all straightened out and used #IF instead of #IFDEF
Jasmine
A: 

I'd look into making it completely dynamic so that you don't have to do anything special at compile time or when building your installer/deployment package. Here's how I'd do it in a commercial winforms app... nothing rocket science about it, but it works:

  1. Have a licensing scheme/mechanism/flag that tells you whether the current user is licensed for Pro or Enterprise. You could even use a "Trial" or "Eval" option as well.

  2. Set up a CurrentUser object (or similar) that tells you the current user's license level. This should be accessible throughout the app.

  3. Use a plugin model so that features/components/capabilities are plugins within the application. As your app's main shell opens up, you load the plugins into the app -- making them appear in the UI the way you want.

  4. Look into creating custom attributes that decorate the classes that represent your plugins. The attribute should indicate the minimum license required for that plugin/feature. When the plugin loader comes across a new plugin, check that plugin's attribute to see what level license is required. If the current user meets (or exceeds) that license, then you load it. If not, you don't.

  5. If you can't separate your features/options/tools into things that can be easily modularized as plugins, you can still use that CurrentUser license level to check things. For example, suppose there's some limit of 100 "widgets" in the Pro version (but not enterprise):

For example:

enum LicenseLevel {
  Eval = 0,
  Pro = 1,
  Enterprise = 2
}

// later...    

for(i=0; i < widgets.Count; i++) {
  if (i == 100 && CurrentUser.LicenseLevel < LicenseLevel.Enterprise)
    break;
  // do stuff
}

Hopefully some combination of the above fits with what you're looking for.

Jeff Donnici
This is pretty much what I currently have, and when I have my proper licensing scheme in place, it's what I'll do, but my current licensing scheme requires two different executables.
Jasmine
A: 

me.yahoo.com guy is spot on.

You can create multiple configurations with compile time definitions.

You can also change the build output directory. By default, you probably have bin/debug and bin/release. There's nothing stopping you from having bin/pro and bin/enterprise output folders (for instance).

Scott P
Yeah I did get that far, but I couldn't figure out how to make the configurations correspond to different code. I think I got it working now...
Jasmine