In Inno Setup installer, uninstall installation made by InstallShield LE - visual-studio-2017

Since the InstallShield LE isn't supported by VS 2017 I'm trying to use Inno Setup instead.
But how can I uninstall previous installations made by InstallShield LE before installation starts using Inno Setup script.
There are multiple versions of the application installed at different users (not on the same computer).
Since the Product Code changes between versions, the GUID in Uninstall registry key can be different and because of that it is hard to find in the uninstall part of registry.

You can use the code from Inno Setup: How to automatically uninstall previous installed version?
While code in the answers is for uninstalling a previous versions installed by Inno Setup, it's mostly generic enough to work with any previous uninstall system.
To make it work with InstallShield, you need to know a Product Code of the release you want to uninstall. If you need to be able to remove any release, you can lookup the Product Code of the actually installed release using the Upgrade Code. For that, you can use a WMI query:
How to find the UpgradeCode and ProductCode of an installed application in Windows 7.
In Inno Setup Pascal Script the code can be like:
const
InstallShieldUpgradeCode = '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}';
function InitializeSetup(): Boolean;
var
WbemLocator, WbemServices, WbemObjectSet: Variant;
Query: string;
ProductCode: string;
begin
WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
WbemServices := WbemLocator.ConnectServer('.', 'root\CIMV2');
Query :=
'SELECT ProductCode FROM Win32_Property ' +
'WHERE Property="UpgradeCode" AND Value="' + InstallShieldUpgradeCode + '"';
WbemObjectSet := WbemServices.ExecQuery(Query);
if not VarIsNull(WbemObjectSet) and (WbemObjectSet.Count > 0) then
begin
ProductCode := WbemObjectSet.ItemIndex(0).ProductCode;
{ Start uninstall here }
end;
Result := True;
end;
Though note that the query can take tens of seconds.

When I wrote the sample script and the related blog post, it was quite clear that you should query the registry to detect previous installed software,
function InitializeSetup(): Boolean;
var
oldVersion: String;
uninstaller: String;
ErrorCode: Integer;
begin
if RegKeyExists(HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F768F6BA-F164-4599-BC26-DCCFC2F76855}_is1') then
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F768F6BA-F164-4599-BC26-DCCFC2F76855}_is1',
'DisplayVersion', oldVersion);
if (CompareVersion(oldVersion, '6.0.0.1004') < 0) then
begin
if MsgBox('Version ' + oldVersion + ' of Code Beautifier Collection is already installed. Continue to use this old version?',
mbConfirmation, MB_YESNO) = IDYES then
begin
Result := False;
end
else
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F768F6BA-F164-4599-BC26-DCCFC2F76855}_is1',
'UninstallString', uninstaller);
ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
Result := True;
end;
end
else
begin
MsgBox('Version ' + oldVersion + ' of Code Beautifier Collection is already installed. This installer will exit.',
mbInformation, MB_OK);
Result := False;
end;
end
else
begin
Result := True;
end;
end;
Your InstallShield based installer should also insert a GUID based subtree to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\, so just analyze what has been there and take necessary actions to uninstall it.
A more recent blog post can be found here.

Related

Python Selenium: XPath changes the encoding of my variables

I has this code that searches through text by XPath. The problem is that the searched text may contain Latin characters like ñor í.
I encoded it and when I print it, it shows perfectly, but when I use the XPath the encoding changes, and obviously it can't be found.
The decoded var prints well:
nombre_act = "HOTEL DIEGO DE ALMAGRO SAN PEDRO DE ATACAMA"
nombre_act = nombre_act.decode("utf8")
nombre_contrato = "Campaña Cyber Day, Desayuno Incluído"
nombre_contrato = nombre_contrato.decode("utf8")
print nombre_contrato
xpath = "//select[#name='"+nombre_act+"']/option[text()='"+nombre_contrato+"']"
print xpath
hotel_sel = driver.find_element_by_xpath(xpath).click()
Your code trials were near perfect. However I feel you don't need to change through encoding/decoding unless you want to print the characters to the console as follows:
nombre_act_actual = "HOTEL DIEGO DE ALMAGRO SAN PEDRO DE ATACAMA"
#nombre_act = nombre_act_actual.encode("utf-8")
nombre_contrato_actual = "Campaña Cyber Day, Desayuno Incluído"
nombre_contrato = nombre_contrato_actual.encode("utf-8") #required as you need to print to the console
print nombre_contrato
xpath = "//select[#name='"+nombre_act_actual+"']/option[text()='"+nombre_contrato_actual+"']"
hotel_sel = driver.find_element_by_xpath(xpath).click()
However, your another issue is the incompatibility between the version of the binaries you are using as follows:
You are using chromedriver=2.41
Release Notes of chromedriver=2.41 clearly mentions the following :
Supports Chrome v67-69
You are using chrome=70.0
Release Notes of ChromeDriver v2.44 clearly mentions the following :
Supports Chrome v69-71
So there is a clear mismatch between ChromeDriver v2.41 and the Chrome Browser v70.0
Solution
Upgrade ChromeDriver to current ChromeDriver v2.44 level.
Keep Chrome version between Chrome v69-71 levels. (as per ChromeDriver v2.44 release notes)
Clean your Project Workspace through your IDE and Rebuild your project with required dependencies only.
If your base Web Client version is too old, then uninstall it through Revo Uninstaller and install a recent GA and released version of Web Client.
Execute your #Test.

How to enumerate the installed StoreApps and their ID in Windows 8 and 10

What I want to get is the AppUserModelId of all installed StoreApp applications, so that I can pass it to IApplicationActivationManager->ActivateApplication.
In Windows 8 it was stored in the Registry, but in Windows 10 it is not anymore.
There are a lot of questions about this in internet but even after days of searching I could not find a satisfying solution.
What I have so far is the following:
I create an instance of IPackageManager,
I call FindPackagesByUserSecurityId() with the SID of the current user,
I iterate through the returned collection
I get an IPackage interface
From that I get an IPackageId interface,
Then I call IPackageId->get_FamilyName()
With that I have for example on Windows 10 for the Windows Calculator the string "Microsoft.WindowsCalculator_8wekyb3d8bbwe".
When I append to this string an "!App" I have the complete AppUserModelId to start the Windows Calculator: "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"
But not all applications use an "!App" behind the FamilyName.
For example Spartan uses the AppUserModelId
"Microsoft.Windows.Spartan_cw5n1h2txyewy!Microsoft.Spartan.Spartan" which does not end with "!App". And when I replace "!Microsoft.Spartan.Spartan" with "!App" it will not start -> "This app does not support the contract specified".
So my question is where do I get the last missing part from?
I found a PowerShell code in internet (http://poshcode.org/5702) that seems to do something very similar:
Get-AppXPackage $PackageName -pv Package |
Get-AppxPackageManifest | % {
foreach($Application in $_.Package.Applications.Application) {
if($Application.Id -like $AppId) {
if($Protocol -and !($Application.Extensions.Extension.Protocol.Name | ? { ($_ + "://") -match (($Protocol -replace '\*','.*') + "(://)?") })) {
continue
}
[PSCustomObject]#{
# Notice the secret magic property:
PSTypeName = "Microsoft.Windows.Appx.Application"
AppUserModelId = $Package.PackageFamilyName + "!" + $Application.Id
}
}
}
}
I really don't understand this cryptic PowerShell stuff, but one line seems interesting to me:
foreach($Application in $_.Package.Applications.Application)
This seems to enumerate Applications in a Package.
A comment in the same PowerShell code says:
# The full AppUserModelId is composed of the package name,
the publisher id, and the app id, such as
Microsoft.ZuneMusic_8wekyb3d8bbwe!Microsoft.ZuneMusic
so what is missing is the $Application.Id.
If I could get an IAppInfo interface anyhow I could call IAppInfo->get_Id() and I would be ready.
But I don't know how to get this from an IPackage in C++.
Incredible that nobody has an idea!
This shows how Microsoft makes us life hard.
Such a universal task like enumerating the installed StoreApps with their AppUserModelId requires a cientific research department.
I finally came to a solution that works perfectly on Windows 8 and Windows 10. But a lot of code is required.
It seems that Windows does not hold the Application ID's in memory and there is no API to determine them directly. I studied all header files in the Windows 10 SDK and could not find a corresponding interface useful for that task.
But I found out how to get them. I continue after the 6 steps in my question:
call IPackage->get_InstalledLocation() which returns an IStorageFolder.
QueryInterface for IStorageItem
call IStorageItem->get_Path()
Now you have the path were the App is installed. Windows 10 uses two base folders:
C:\Program Files\WindowsApps
C:\Windows\SystemApps
and several others like
C:\Windows\vpnplugins
C:\Windows\devicesflow
C:\Windows\MicracastView
C:\Windows\PrintDialog
C:\Windows\PrintDialog3D
C:\Windows\WinStore
In the returned folder path you will find a file "AppxManifest.xml".
This file looks like:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns=".....">
......
......
<Applications>
<Application Id="microsoft.windowslive.mail" Executable="HxMail.exe" EntryPoint="Executable">
......
......
</Application>
<Application Id="microsoft.windowslive.calendar" Executable="HxCalendarAppImm.exe" EntryPoint="Executable">
......
......
</Application>
</Applications>
</Package>
And voilà, there they are. This package has two application ID's: "microsoft.windowslive.mail" and "microsoft.windowslive.calendar".
Then you take the package's FamilyName from step 6 append an "!" and append this ID and you are done.
This package can be started with IApplicationActivationManager->ActivateApplication() using one of the AppUserModelId's:
"microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar"
"microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail"
Use PackageManager APIs to enumerate packages and GetPackageApplicationIds to enumerate applications in a package e.g. pseudo-code
FOREACH p IN PackageManager.FindPackagesForUserWithPackageTypes(null,
PackageType_Main|PackageType_Optional)
{
PACKAGE_INFO_REFERENCE pir
OpenPackageInfoByFullName(p.Id.FullName, 0, &pir)
UINT32 n=0
GetPackageApplicationIds(pir, &n, null, null)
BYTE* buffer = new BYTE[n]
UINT32 count=0
GetPackageApplicationIds(pir, &n, buffer, &count)
ClosePackageInfo(pir)
PCWSTR * applicationUserModelIds = reinterpret_cast<PCWSTR*>(buffer);
FOR (i=0; i<count; ++i)
{
PCWSTR applicationUserModelId = applicationUserModelIds[i]
}
delete [] buffer
}
See GetPackageApplicationIds() on MSDN for more details including working sample code
https://msdn.microsoft.com/en-us/library/windows/desktop/dn270603(v=vs.85).aspx

Aurelius Titan and Elasticsearch CONTAINS_REGEX not giving results

I have a basic Titan instance running on Cassandra with elastic search for full-text indexing (se below for setup).
Elastic search index does not appear to return correctly when using CONTAINS_REGEX when the string parameter does not contain any sepertors like whitespace or ..
Example:
g.V().has('name', "somename") //This exist
==> v[123456]
g.V().has('name', CONTAINS_REGEX, ".*somename.*") //This does not find the vertex.
==> null
g.V().has('name', CONTAINS_REGEX, ".*omenam.*") //Nor does this..
==> null
g.V().has('name', CONTAINS_REGEX, "somename") //Or this..
==> null
g.V().has('name', CONTAINS_REGEX, "^somename$") //String start + end does not work.
==> null
g.V().has('name', "somename.two") //If the name has a separator in it, then CONTAINS_REGEX works as expected
==> v[23456]
g.V().has('name', CONTAINS_REGEX, ".*somename.*")
==> v[23456]
g.V().has('name', CONTAINS_REGEX, ".*omenam.*")
==> v[23456]
g.V().has('name', CONTAINS_REGEX, "somename\\.two")
==> v[23456]
//Changing to the new syntax also does not work as expected.
g.query().has('name', CONTAINS_REGEX, ".*somename.*").vertices()
So, as you can see, CONTAINS_REGEX does not appear to behave correctly when the string does not contain any whitespace or other separators. This has worked on previous versions (0.4.X). Maybe something has changed that I am not aware of, and this should be done differently now. I was not able to find anything in the docs however. It could also be that there are some settings in either titan or ES I have not set up correctly, but again, I could not find anything.
Any help would be greatly appreciated :)
I am inserting the names like this:
def get_or_create_name(g, name)
{
nv = g.V('name', name);
if(!nv.hasNext())
{
ret = g.addVertexWithLabel('name');
ElementHelper.setProperties(ret, 'name', name);
}
else
{
ret = nv.next();
}
ret
}
Using:
Titan 0.5.2
Debian 7.6
Java java version "1.7.0_65", OpenJDK Runtime Environment (IcedTea 2.5.1) (7u65-2.5.1-5~deb7u1), OpenJDK 64-Bit Server VM (build 24.65-b04, mixed mode)
Indexing part of db schema:
name_label = mgmt.makeVertexLabel("name").make()
name = mgmt.makePropertyKey('name').dataType(String.class).make()
name_uniqueness = mgmt.buildIndex("name_uniqueness",Vertex.class).addKey(name).unique().buildCompositeIndex();
mgmt.setConsistency(name_uniqueness, ConsistencyModifier.DEFAULT); //Not sure if this is needed
mgmt.buildIndex('name_index',Vertex.class).addKey(name,Mapping.TEXT.getParameter()).buildMixedIndex("search")
Small note: I am aware that I could use Mapping.STRING.getParameter() in stead of TEXT, and then use g.V().has('name', REGEX, ".*somename.*"), but I was never able to get the string index to work at all. I am also aware CONTAINS_REGEX is intended for use on each word within a longer text, but again, I was never able to get the string version to work.
After digging through error logs and testing lots of stuff I found that the issue was that some of the java-processes were running out of memory. Specifically Rexster.
What I did was increase the available memory and tweak the java options a bit.
Thus, in bin/rexster.sh I changed this line:
JAVA_OPTIONS="-server -Xms128m -Xmx512m -Dtitan.logdir=$LOG_DIR"
To:
JAVA_OPTIONS="-server -Xms128m -Xmx2g -XX:-UseConcMarkSweepGC -Dtitan.logdir=$LOG_DIR"
And now everything seems to be working nicely! :)
To recap: The issue was that Rexster crashed between storing to cassandra and the initialization of the elasticsearch index because of lack of ram.

Manually specify location of .vagrant folder in Vagrantfile

The folder where I have Vagrantfile is being auto-generated during the build, so it gets cleaned up, but I'd like to still be able to use the created machines. The easiest way would be to put .vagrant folder somewhere outside the auto-generated folder. Is this possible?
You have (at least) two options:
Use VAGRANT_DOTFILE_PATH to set the the location where the project specific data is stored (defaults to .vagrant as you already know). Note that the path has to be project/Vagrantfile specific.
cd to a directory where you want the .vagrant directory to be created, and use VAGRANT_VAGRANTFILE to specify the path to the generated Vagrantfile.
I know this is an old question, but for anyone arriving here via Google, there is a workaround if you really want to specify the metadata directory without mucking about with environment variables each time. Just put this in the top of your Vagrantfile:
VAGRANT_DOTFILE_PATH = 'custom/dotfile/path'
if(ENV['VAGRANT_DOTFILE_PATH'].nil? && '.vagrant' != VAGRANT_DOTFILE_PATH)
puts 'changing metadata directory to ' + VAGRANT_DOTFILE_PATH
ENV['VAGRANT_DOTFILE_PATH'] = VAGRANT_DOTFILE_PATH
puts 'removing default metadata directory ' + FileUtils.rm_r('.vagrant').join("\n")
system 'vagrant ' + ARGV.join(' ')
ENV['VAGRANT_DOTFILE_PATH'] = nil #for good measure
abort 'Finished'
end
I wanted each provider to use a separate Vagrant directory to easily be able to swap between them. I could not get #hairraisin's solution to work, but based on that I ended up with the following:
Vagrant.configure('2') do |config|
config.vm.provider :lxd do |lxd, override|
if ENV['VAGRANT_DOTFILE_PATH'].nil?
ENV['VAGRANT_DOTFILE_PATH'] = '.vagrant-lxd'
puts 'Removing default metadata directory ' + FileUtils.rm_r('.vagrant').join("\n")
exec 'vagrant ' + ARGV.map{|arg| Shellwords.escape arg}.join(' ')
end
…
This avoids endless recursion or aborting too early. exec rather than system avoids a non-zero exit code from every vagrant command.

Force visual studio to error on include with incorrect capatilization [duplicate]

If you have a header file named ThisIsAHeaderFile.h, the following will still locate the file in Visual Studio:
#include <ThisIsAheaderFile.h>
Is there a way to enforce case sensitivity so that the #include will result in an error?
You can't, because the Windows file system is itself case-insensitive.
If you could get into a situation where you had both RICHIE.h and richie.h, it might make sense to control case sensitivity, but you can't.
I would like to point out that this is not an unsolvable problem as many tries to point out to the OP. The case insensitivity is beside the point. The point is as Lorenz03Tx explains in a comment, even though the file system is case insentitive the case is retained, so it can be controlled.
Such a counter measures is really great to have when doing cross platform development, and prevents much after work when the code is compiled for the other platform. Not to forget that making the build process more picky you would induce better habits for the developers, as they gradually will be more consistent how they include and name files.
TL;DR
One solution is to use a script that simply scans the source files for include statements and tries to match them along the include paths. Such a script could be added to visual studio post-build events, and thus run at every build, or (inspired by krlmlr) use the preprocessor of a compiler that enforce case sensitivity.
It is (used to be?) possible to create files with the same name but case differences on NTFS. Maybe someone with cygwin can verify this.
MSDN
Even then, however, it's impossible to access more than one of these at a time from a normal Windows application.
While it might not be possible to enforce this from within Visual Studio, one could implement a quick check by running only the preprocessor on the C/C++ source. This will run quickly enough to be practicable even as post-commit hook in a version control system, and err if the case in file names has been mismatched. So:
Configure your build system in Linux to support preprocessor-only runs (-E with gcc/g++)
Implement a preprocessor-only run as post-commit hook, triggering an early notification to the responsible person and/or to someone willing to routinely fix these errors
Of course, this assumes a VCS as central storage for the code.
Both FAT and NTFS are case insensitive file systems. Foo and fOO are the same file as far as they are concerned. Although the Windows OS will preserve the case you use for a file. If you name a file ThisIsAheaderFile.h it will show up that way in the file system. Although all system function calls to open that file can use any casing they want.
Also having similar problem when trying to build under linux; not full solution...
If you Find in Files #include by VS and copy result to textarea, you will get sorted CSV with include file name, original path and list of files in 3rd column (columns are tab delimited)
Easy to check solution/wide and in case there are not much case problems it should be easy to replace them?
function readIncludes(t)
{
var s = t.value.split('\n');
var res = {};
for(var r in s)
{
if (r == 0) continue;
var dq = s[r].indexOf('(');
var p = s[r].substr(0, dq);
var p2 = s[r].indexOf(':', dq);
p2 = s[r].substring(0, p2);
dq = s[r].indexOf('#', dq);
var i = s[r].substr(dq);
var ip = i.replace(/#include\s+/, "");
if (!ip) continue; // *#includes.*
var st = '<>""';
if (st.indexOf(ip[0]) < 0) continue; // *#include*\S+
st = st[st.indexOf(ip[0]) + 1];
ip = ip.substr(1, ip.indexOf(st, 2) - 1);
if (!ip || ip[0] == '/') debugger
if (!res[ip]) res[ip] = [];
res[ip].push(p2);
}
var resSorted = [];
for(var r in res)
{
var shortR = r.replace(/.+[\\/]/, ""); // include file
resSorted.push(shortR + "\t" + r + "\t" + res[r]); // \tpath\tplaces
}
t.value = resSorted.sort().join('\n'); // sort again long lines of results
}
html,body,textarea {
width: 100%;
height: 100%;
white-space: nowrap;
}
<textarea onchange="readIncludes(this)">
</textarea>