Using Inno Setup, I'm trying to check to see if the .NET 4.8 runtime is installed on a Windows computer. If it is not installed, I run the .NET 4.8 runtime installer exe file. According to Microsoft, you can check the registry at a certain location and look at a certain value to see which specific version of .NET is installed. Inno Setup has a function called RegQueryStringValue which grabs a value from the registry:
https://jrsoftware.org/ishelp/index.php?topic=isxfunc_regquerystringvalue
I am following that API correctly, as far as I'm aware. I have also confirmed, using regedit, that this registry key and value do exist on my system. However, when I run Inno Setup, it fails to find the registry value. Here is my code:
function IsDotnet48Installed: boolean;
var
valueStr: string;
valueInt: integer;
begin
if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', valueStr) then
begin
MsgBox('.NET 4.8 registry value is: "' + valueStr + '"', mbInformation, MB_OK);
valueInt := StrToInt(valueStr);
if valueInt >= 528040 then
result := true
else
result := false
end
else
MsgBox('Unable to find .NET 4.8 registry key', mbInformation, MB_OK);
end;
When the above code is ran, the RegQueryStringValue function returns false, and I thus get the message box that says "Unable to find .NET 4.8 registry key". I am not sure what I am doing wrong.
Thank you.
#LexiLi 's comment to the original question is the answer.
Instead of using the function RegQueryStringValue I used the function RegQueryDWordValue. Worked on the first try.
https://jrsoftware.org/ishelp/index.php?topic=isxfunc_regquerydwordvalue
Related
Can language service for the 'release 1.3' typescript branch be used as a drop-in replacement in the current Visual Studio plugin? I would like to try out the 1.3 compiler and would like to have Visual Studio use the new language service, is this possible? I tried to copy the typescriptServies.js into the TS language service plugin, but this makes VS lose all completion for TS.
The API is different than before, so that would not be impossible.
However the opensource editor called CATS right now has support for TypeScript 1.3 in the latest unstable release. You can download that from here:
https://github.com/jbaron/cats/releases
Some of the new features you could try out then are (all part of the latest TS master branch):
Protected members
Union Types
Support for ES6 (block scoping etc)
BTW I'm one of the developers of CATS. So although not too much effort migrating from 1.0.1 to 1.3, it was still for sure not a drop-in replacement. Also the current master branch still has a few methods that throw not-yet-implemented exceptions, so some special precautions are required to avoid them.
I don't think that will work. I believe VS uses the LanguageService interface found here:
services.ts 1.3 for the 1.3 version. If you compare it to the 1.1 version of the LanguageService the interface itself is mostly the same (getTypeAtPosition is gone and replaced by getQuickInfoAtPosition and so on) but other interfaces changed too (see below for the CompletionEntryDetails interface).
I tried replacing it myself and for example renames won't work either ("Unknown type at caret position" or something).
//1.1
export interface CompletionEntryDetails {
name: string;
kind: string; // see ScriptElementKind
kindModifiers: string; // see ScriptElementKindModifier, comma separated
type: string;
fullSymbolName: string;
docComment: string;
}
//1.3
export interface CompletionEntryDetails {
name: string;
kind: string; // see ScriptElementKind
kindModifiers: string; // see ScriptElementKindModifier, comma separated
displayParts: SymbolDisplayPart[];
documentation: SymbolDisplayPart[];
}
I'm wanting to get some information from a dll a program I'm debugging is linked to:
So - I noticed that my debugger downloaded a pdb for a library where a crash happens, and I tried to run dia2dump on it:
dia2dump -all mfc90.i386.pdb\05089943A3B2462891FBF83E29A72618E\mfc90.i386.pd_
But dia2dump replies:
loadDataForExe failed - HRESULT = 806d0012
I don't know what that error message means... but I think (guess) it's because my msdia.dll is too old a version because I can dump the pdb's from older dll's that are at the 80's level; and I checked the dia.dll I installed and it's msdia80.dll, So -- I went and got msdia90.dll -- and I have now registered (regsvr32.exe msdia90.dll) and so I have installed both dia80.dll and dia90.dll. However, the dia2dump only co-creates the dia80.dll at run time .... and even if I unregister it, but leave dia90 registered -- dia2dump will then complain it can't find the dll at all. ( CoCreateInstance failed - HRESULT = 80040154 )
I'm not sure if this is because I am on a 32 bit machine, or because I am compiling under VS2008... or I registered the wrong dia90.dll somehow... or what? How do I figure it out?
This is what I've tried so far:
I modified dia2dump.cpp to load the dll based on a the __uuid() of a forward reference to the class DiaSource; I hoped that the __uuid() would be able to find the active version of the class in the registry and supply the correct number, but VS2008 apparently doesn't work that way -- it computes the __uuidof() in some other fashion ... because even with diaguid.Lib deleted, and CLSID_DiaSource becoming undefined (I verified it can't find it.) using __uuidof(DiaSource) still caused it to find the CLSID for msdia80.dll -- not 90.
typedef class DiaSource;
hr = CoCreateInstance(__uuidof(DiaSource),//CLSID_DiaSource,
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IDiaDataSource),
(void **) ppSource);
So, why is this not also linking to the CLSID for msdia90.dll ?
I don't have the diaguid.Lib for version 90 -- just the dll. But I do know, in the registry that there are two uuid's / CLSID's -- one for each version of the dll.
HKEY_CLASSES_ROOT/CLSID/4C41678E-887B-4365-A09E-925D28DB33C2 # msdia90.dll
HKEY_CLASSES_ROOT/CLSID/BCE36434-2C24-499E-BF49-8BD99B0EEB68 # msdia80.dll
Although, in the latest MSDN page at this time (2013), the name of the variable is still CLSID_DiaSource , suggesting the class is named the same in the new dll... So I don't know why there are two different CLSID's for the dll's...
http://msdn.microsoft.com/en-us/library/hd8h6f46%28v=vs.120%29.aspx
EDIT:
I got it to link (CoCreate), I think, by doing this trick as a work-around, but the original error still happens when I run it with version 90 -- so my guess was wrong...
class __declspec(uuid("4C41678E-887B-4365-A09E-925D28DB33C2")) msdia90;
hr = CoCreateInstance(__uuidof( msdia90 ),
So, I'm totally lost. Why cant dia2dump.exe work on a downloaded mfc90.pdb file?
My product has a helper executable to uninstall all related sub-products. I uninstall based on upgrade codes of all sub-products.
First, I fetch the product code from upgrade code using MsiEnumRelatedProducts function. Then I try to uninstall the product using MsiConfigureProductEx function.
The problem is MsiConfigureProductEx is returning error.
Invoked Function: MsiConfigureProductsEx
Return Code: 1605 (0x00000645)
Description: This action is only valid for products that are currently installed.
Why is MsiEnumRelatedProducts returning a invalid product code ? I searched through the windows registry to see if such product code exists. There isn't any. How to debug the issue ?
Edit: Added minimum code that reproduces issue.
// UpgradeCodes is an array having upgrade codes of all modules.
TCHAR lpProductCode[GUID_STR_LENGTH];
const TCHAR tszNoReboot[] = _T("REMOVE=ALL REBOOT=ReallySuppress DISABLE_REBOOT_PROMPT=1");
for (size_t i = 0; i < sizeof(UpgradeCodes) / sizeof(UpgradeCodes[0]); i++)
{
tstring tstrUpgradeCode = UpgradeCodes[i];
DWORD dwIndex = 0;
size_t status;
// for each of the upgrade code, get all the products
do
{
status = MsiEnumRelatedProducts(UpgradeCodes[i],
0,
dwIndex,
lpProductCode);
if (ERROR_SUCCESS == status)
{
UINT uiReturn = MsiConfigureProductEx(lpProductCode,
INSTALLLEVEL_DEFAULT,
INSTALLSTATE_DEFAULT,
tszNoReboot);
if (ERROR_SUCCESS_REBOOT_REQUIRED == uiReturn)
{
// prompt for reboot at the end of all modules uninstallation.
}
if (ERROR_SUCCESS != uiReturn)
{
// log message with return code.
// Error Code: 1605 is coming from here.
}
}
}while (ERROR_NO_MORE_ITEMS != status);
}
Some years have passed and I want to add two scipts that can be used
to export MSI package information:
How can I find the product GUID of an installed MSI setup? - in section 2.
Do visit the link above, but here are direct links to the scripts:
1) the html export version and 2) the simpler text output.
Disclaimer: The below information is very "under the hood". Please use API calls whenever you can to access the MSI database. Also remember to run all your MSI testing on virtual machines so you can easily revert to a "clean state". During MSI development strange things can happen.
It is possible that a previous uninstall of that product of yours left something registered upon uninstall, and this is causing all the problems. I would try to check with scripts what is registered on the system.
Found good discussions of retrieving product info with VBScript here, a couple of really good scripts - recommended. Go to the sites to find the scripts, they format pretty poorly here and clog the answer.
http://forum.installsite.net/index.php?act=ST&f=26&t=14035
http://www.dwarfsoft.com/blog/2010/06/22/msi-package-code-fun/
The Windows Installer database is mostly located here:
HKEY_CLASSES_ROOT\Installer\
The upgrade code section: HKEY_CLASSES_ROOT\Installer\UpgradeCodes
You must never touch anything in the Windows Installer Database Registry directly. It's extremely interconnected and easy to corrupt. Only go through the APIs. Note that the GUIDs in the registry are packed, so you won't find the GUIDs from the package in the registry.
Packed GUID: 03B1692A57845354EA63AD602436AB05
Regular GUID: {A2961B30-4875-4535-AE36-DA064263BA50}
Using the VBScripts above and the registry data directly for inspection you should be able to determine what is happening in the Windows Installer database.
I would never work straight in C++ to test this out. Instead I would eliminate some complexity by trying PowerShell or VBScript to determine what is wrong with the uninstall routine. You can find information on how to use these scripting tools here in this thread. And here is another thread.
It is not quite clear if some of the uninstalls work, and there is
one that fails or if the uninstall operation fails altogether? That's
the first question.
Have you tried manually uninstalling all products from add/remove to ensure they all uninstall correctly manually? One of the products could trigger an error return code during uninstall that is caught programatically, but is ignored during manual install. Often these can be from Custom Actions placed after InstallFinalize. In this case some setup redesign is called for. In the simplest case it would involve disabling error checking for the custom action, but that fix is not good enough in my opinion.
It is possible that the product is
installed, but per-user. In other words it might be installed only
for a single user on the machine, and not for the machine (this is controlled by the ALLUSERS property). I am not sure how this function works if this is the case - it may even report the product as advertised (available for on demand install via a shortcut, but not actually installed). Again, I have not tried this, and uninstall may still work. Just off the top of my head to try and give you some pointers.
Have you performed any major upgrades of existing MSI files as part of the install of your product?
One further question: are you running on Windows 8? And are these MSI files generated with WIX or some other tool? There have been some intermittent reports on problems that appear at least remotely similar.
If you have a package installer (like Microsoft SQL Server), it can install a host of other items during its installation phase.
Later, when you go to uninstall the big package installer, all of the items that installer added to the system should theoretically be removed.
So, try just uninstalling your application, stop, then look to see if the other smaller applications are still on the system.
If they are, then you will need to uninstall these individual applications first when your custom uninstall script starts.
I assume you already have a System.Configuration.Install.Installer class. Follow a set of steps when installing your application (1, 2, 3, etc.), then perform these steps in reverse order when uninstalling your application (3, 2, 1).
Trying a new approach for you. I have located two products that seem to have at least two productcodes registered for their upgrade codes. They are: MSVC redistributable 2008 and MSXML 4.0 SP2. I have written a small C++ test that seems to work ok.
Essentially I think you need to check for ERROR_NO_MORE_ITEMS before the next iteration of the loop so you don't try to uninstall products that are no longer installed.
Here is some VS2013 code that should compile out of the box on a fresh install, empty project.
UPDATE: updated code to use VS2017 and a minimal console application.
Create a new console project: File => New => Project... => Visual C++, Windows Desktop, Windows Console Application
Paste the below code into the main CPP file (replacing whatever is there)
Set a breakpoint and build & run (F5)
F10 to step through
If "Microsoft Visual C++ 2008 Redistributable" isn't installed, no related product codes will be found.
#pragma once
#include "stdafx.h"
// The below should really be in stdafx.h (precompiled header)
#define WIN32_LEAN_AND_MEAN // Exclude stuff from Windows.h
#define STRICT
#include <windows.h>
#include <msi.h>
#pragma comment(lib, "msi.lib") // To make code link
int main()
{
UINT i = 0;
UINT status = ERROR_SUCCESS;
TCHAR productcode[39] = {};
const TCHAR upgradecode[39] = L"{AA783A14-A7A3-3D33-95F0-9A351D530011}"; //Microsoft Visual C++ 2008 Redistributable
//const TCHAR upgradecode[39] = L"{7CE723E3-E56B-432C-9F24-78C0606045A5}"; // MSXML 4.0 SP2 (KB973688)
do
{
// look up (related) product code(s) for specified upgrade code
status = MsiEnumRelatedProducts(upgradecode, 0, i, productcode);
if (status == ERROR_NO_MORE_ITEMS) // Test here. 259, ERROR_NO_MORE_ITEMS
{
// No more productcodes for specified upgrade code
MessageBox(NULL, L"No more productcodes", L"Done", MB_OK);
break; // exit do-while loop
}
i++; // Next product code
MessageBox(NULL, productcode, L"Product Code:", MB_OK);
} while (status != ERROR_NO_MORE_ITEMS);
return 0;
}
There could be erronously registered products on your system due to failed major upgrades or similar advanced error scenarios, so I am not sure if this solves your problem.
Keep in mind that the Windows Installer Database at HKEY_CLASSES_ROOT\Installer\UpgradeCodes contains packed GUIDs. You can try the VBScript code found in the following link to convert back and forth between packed and regular GUID formats: http://www.symantec.com/connect/blogs/guid-converter
More info on guid formats here if it is interesting: http://www.symantec.com/connect/articles/working-darwin-descriptors
// TEST DATA 2014 (guids in different formats):
// UpgradeCode
// 41A387AA3A7A33D3590FA953D1350011 => {AA783A14-A7A3-3D33-95F0-9A351D530011}
//
// ProductCode
//
// Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148
// CFD2C1F142D260E3CB8B271543DA9F98 => {1F1C2DFC-2D24-3E06-BCB8-725134ADF989}
//
// Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.17
// D20352A90C039D93DBF6126ECE614057 => {9A25302D-30C0-39D9-BD6F-21E6EC160475}
// UpgradeCode
// 3E327EC7B65EC234F942870C0606545A => {7CE723E3-E56B-432C-9F24-78C0606045A5}
//
// ProductCode
//
// MSXML 4.0 SP2 (KB973688)
// 6E8A266FCD4F2A1409E1C8110F44DBCE => {F662A8E6-F4DC-41A2-901E-8C11F044BDEC}
// MSXML 4.0 SP2 (KB954430)
// DDA39468D428E8B4DB27C8D5DC5CA217 => {86493ADD-824D-4B8E-BD72-8C5DCDC52A71}
I am getting the following error using xcode with pascal:
warning: It seems your project only contains units and no main program
What causes this warning? And how do I set the main program?
I am using: Xcode 4.5.2, Free Pascal Compiler version 2.6.0, and Mac OSX 10.8.
If I understand the problem correctly, you're missing the .dpr (project file) that tells the compiler what type of project it should be building. The project file for Delphi (and the Borland Pascal and Turbo Pascal compilers before it) typically look something like:
{ For a GUI (Windows) application }
program MyProgram;
uses
Forms,
main in 'main.pas' {fMain};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TfMain, fMain);
Application.Run;
end.
{ For a console application }
program MyProgram;
{$APPTYPE CONSOLE }
uses
MyMain, SysUtils;
begin
try
{
Execute your application's entry point (main()) here, in this case
contained in MyMain.pas that's listed in the uses clause above.
}
except
{ Handle any exception here }
end;
end.
In Delphi XE2, you then run dpr2xcode.exe to create a corresponding Xcode project. (I don't know what the corresponding step would be in FreePascal, but you might look for something like that in your FP install.) Open that .xcodeproj file in Xcode on the Mac, and then run or debug the code.
For specific info on using FreePascal and Xcode, I recommend a series of articles by Phil Hess.
I have created an application on Delphi 7. my app had running fine since yesterday. I don't know what's happened yesterday which cause my application halts on Application.Initialize line in source code and does not return to next line when i trace the program. I can't run the created executable file from widows niether while the generated file does run on another machine correctly. here is the code where the compiler stops on it:
program Info_Kiosk;
uses SysUtils, Forms, ... (some other units) ;
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(Tfrm_Main, frm_Main);
any help would be appreciated
The implementation of TApplication.Initialize looks like this:
procedure TApplication.Initialize;
begin
if InitProc <> nil then TProcedure(InitProc);
end;
So, look through your code for anything that assigns to InitProc.
Another approach is to use your debugger to help you. Enable Debug DCUs. Then set a break point on the call to Application.Initialize in your .dpr file. Then step into that procedure with F7. Then step into the call to InitProc and follow that along until you reach the code that blocks.
If you are using a revision control system you can simply check out older versions of the project and use a binary search to find the commit that introduced the behaviour. If you are not using revision control, start doing so now.