I want to extract the "Product Version" number (of the form aa.bb.cccc) that you type in the General settings of an InstallShield Limited Edition deployment project.
Specifically I want to do this in a custom pre-build step. Ideally I'd code this as an executable written in C++ using WinAPI.
Waiting until the post build step and extracting it from the registry is too late - it needs to happen before the project files are copied.
Is there a way to do this? I don't know of a macro that InstallShield defines for that. It could simply be that it is not supported in the free version.
If you really need to do this pre-build then you're pretty much out of luck I'm afraid since the relevant options are disabled in the limited edition.
However, once installation is complete, you can extract the version from the windows registry and touch any of the files that the installer has dropped. Here's some code you can use to do the first part:
static const std::string key = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; // Arguably the best place from which to obtain msi version data
static const unsigned MAX_KEY_LENGTH = 255; // Maximum length of a registry key
static const std::string displayName = /*ToDo - your display name here*/
static const unsigned displayNameSize = /*ToDo - the size of the display name here + 1 for the null terminator*/
int g_version; // The version number as it appears in the registry
HKEY hKey = NULL;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_ENUMERATE_SUB_KEYS, &hKey) == ERROR_SUCCESS){
for (DWORD Index = 0; g_version == 0U; ++Index){
DWORD cName = 256;
char SubKeyName[MAX_KEY_LENGTH + 1/*Maximum length of a registry key is 255, add 1 for termination*/];
if (RegEnumKeyEx(hKey, Index, SubKeyName, &cName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS){
break;
}
HKEY hSubKey = NULL;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (key + "\\" + SubKeyName).c_str(), 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS){
// Is the DisplayName equal to displayName?
DWORD dwType = REG_SZ;
TBYTE buf[displayNameSize];
DWORD dwSize = displayNameSize;
HRESULT res;
if ((res = RegQueryValueEx(hSubKey, TEXT("DisplayName"), NULL, &dwType, (PBYTE)&buf, &dwSize)) == ERROR_SUCCESS){
if (!::strncmp(displayName.c_str(), (PTCHAR)buf, displayNameSize)){
// get the version
dwType = REG_DWORD;
dwSize = displayNameSize;
if (RegQueryValueEx(hSubKey, TEXT("Version"), NULL, &dwType, (PBYTE)&buf, &dwSize) == ERROR_SUCCESS && dwType == REG_DWORD){
g_version = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
}
}
}
RegCloseKey(hSubKey);
}
}
RegCloseKey(hKey);
}
You've already mentioned you'll code this in an executable. This can run as a post-build step and the limited edition supports that. Then all you need to do is embed the version number into one of your installation files; which your executable will be able to do.