Recent

Author Topic: Getting the list of installed programs  (Read 13865 times)

mrkaban

  • Jr. Member
  • **
  • Posts: 60
    • КонтинентСвободы
Getting the list of installed programs
« on: September 10, 2016, 09:52:03 am »
Hello, thank you all very much for your help repeatedly!

Tell me please. At the moment, I get a list of the registry keys in a variable of type names tstringlist method GetKeyNames (MyList).

I need to get to MyList list of program names, ie, the parameters of these key "DisplayName". I found even GetDataInfo method ( 'DisplayName', MyDataInfo).

But I can not figure out how to make it work.

Here is the code without GetDataInfo
Code: Pascal  [Select][+][-]
  1.  MyRegistry:=TRegistry.Create;      
  2.       MyList:=TStringList.Create;
  3.           with MyRegistry do
  4.              begin
  5.              RootKey:=HKEY_LOCAL_MACHINE;
  6.              if OpenKey('Software\Microsoft\Windows\CurrentVersion\Uninstall',
  7.              False)=True then GetKeyNames(MyList);  
  8.              CloseKey;
  9.                end;
  10.  

Please tell me how to convert code to variable values contained Mylist DisplayName parameters.

Thanks in advance!

On the Internet, I found here such code, but alter it so that it worked, I did not succeed.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.    MyList: TStringList;
  4.    MyRegistry: TRegistry;
  5.    i: Integer;
  6.    Str: string;
  7.        
  8.  begin
  9.      MyRegistry:=TRegistry.Create;
  10.      MyList:=TStringList.Create;
  11.          with MyRegistry do
  12.             begin
  13.             RootKey:=HKEY_LOCAL_MACHINE;
  14.             if OpenKey('Software\Microsoft\Windows\CurrentVersion\Uninstall',
  15.             False)=True then GetKeyNames(MyList);
  16.             CloseKey;
  17.             for i:=0 to MyList.Count-1 do
  18.                begin
  19.                RootKey:=HKEY_LOCAL_MACHINE;
  20.                OpenKey('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+
  21.                MyList[i], False);
  22.                Str:=ReadString('DisplayName');
  23.                if Str<>'' then
  24.                Memo1.Lines.Add(ReadString('DisplayName'));
  25.                CloseKey;
  26.                end;
  27.               end;
  28.  end;

Angus

  • New Member
  • *
  • Posts: 16
Re: Getting the list of installed programs
« Reply #1 on: September 13, 2016, 01:27:33 pm »
Hi, HKEY_LOCAL_MACHINE requires special privileges, and is considerd a security feature on Windows.  Use the OpenKeyReadOnly method and your code will work. See modified version below.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.    MyList: TStringList;
  4.    MyRegistry: TRegistry;
  5.    i: Integer;
  6.    Str: string;
  7.  
  8.  begin
  9.      MyRegistry:=TRegistry.Create;
  10.      MyList:=TStringList.Create;
  11.          with MyRegistry do
  12.             begin
  13.             RootKey:=HKEY_LOCAL_MACHINE;
  14.             OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Uninstall');
  15.             GetKeyNames(MyList);
  16.             CloseKey;
  17.             for i:=0 to MyList.Count-1 do
  18.                begin
  19.                RootKey:=HKEY_LOCAL_MACHINE;
  20.                OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+
  21.                MyList[i]);
  22.                Str:=ReadString('DisplayName');
  23.                if Str<>'' then
  24.                Memo1.Lines.Add(ReadString('DisplayName'));
  25.                CloseKey;
  26.                end;
  27.               end;
  28. end;
  29.  
  30. end.

Angus

  • New Member
  • *
  • Posts: 16
Re: Getting the list of installed programs
« Reply #2 on: September 13, 2016, 01:34:03 pm »
Additionally it may be a good idea to free up the resources you created, see below:
Code: Pascal  [Select][+][-]
  1.      MyRegistry:=TRegistry.Create;
  2.      MyList:=TStringList.Create;
  3.      try
  4.      with MyRegistry do
  5.            
  6.             //your code in here
  7.  
  8.      finally
  9.        MyRegistry.Free;
  10.        MyList.Free;
  11.      end;    

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Getting the list of installed programs
« Reply #3 on: September 13, 2016, 01:45:18 pm »
Also... on a 64bit OS you have two locations for Uninstall.
For 64bit programs:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
and for 32bit programs:
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall

It would also depend if you're using 64bit Lazarus which one you get by default.

On Laz64bit on 64bit OS you get (64bit programs)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
when you access
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
and (32bit programs)
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
when you access
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall

On Laz32bit on 64bit OS you get (32bit programs)
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
when you access
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
and
you need to add KEY_WOW64_64KEY flag when opening the registry to access the 64bit-part.

So if you use 32bit Lazarus you might end up with only the 32bit programs if you're not careful.

mrkaban

  • Jr. Member
  • **
  • Posts: 60
    • КонтинентСвободы
Re: Getting the list of installed programs
« Reply #4 on: September 13, 2016, 03:10:53 pm »
Please tell me how to correctly add the result is not in the memo, and TStringList?

Code: Pascal  [Select][+][-]
  1.    for i:=0 to MyList.Count-1 do
  2.            begin
  3.            RootKey:=HKEY_LOCAL_MACHINE;
  4.            OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+
  5.            MyList[i]);
  6.            Str:=ReadString('DisplayName');
  7.            if Str<>'' then
  8.            MyList2.Add(ReadString('DisplayName'));
  9.            CloseKey;
  10.            end;

a memo came to write and read, but I would be more convenient to read from a TStringList.

In this way, as I wrote more when reading problem. The problem is that not the entire list climbed.

as though cut off. It can of course read the problem ... But a memo like to work. In any case, here I am read out ...

 
Code: Pascal  [Select][+][-]
  1.              with MyList2.Create do
  2.   try
  3.     MyList2.StrictDelimiter := true;
  4.     s := '';
  5.     for i := 0 to MyList2.Count - 1 do if Trim(MyList2.Strings[i]) <> '' then
  6.       s := s + Format('%s(name LIKE "%%%s%%")', [IfThen(i = 0, '', ' OR '), MyList2.Strings[i]]);
  7.     s := 'SELECT * FROM program WHERE ' + s + ' ORDER BY id';
  8.   finally
  9. //    Free;
  10.   end;          
  11.  
  12. SQLQuery1.Close;
  13. SQLQuery1.Active:=false;
  14. SQLQuery1.SQL.Clear;
  15. SQLQuery1.SQL.Add(s);
  16. SQLQuery1.Active:=true;
  17. SQLQuery1.Open;

Спасибо большое за подсказки!!!

mrkaban

  • Jr. Member
  • **
  • Posts: 60
    • КонтинентСвободы
Re: Getting the list of installed programs
« Reply #5 on: September 21, 2016, 03:29:08 pm »
Also... on a 64bit OS you have two locations for Uninstall.
For 64bit programs:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
and for 32bit programs:
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall

It would also depend if you're using 64bit Lazarus which one you get by default.

On Laz64bit on 64bit OS you get (64bit programs)
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
when you access
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
and (32bit programs)
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
when you access
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall

On Laz32bit on 64bit OS you get (32bit programs)
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
when you access
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\
and
you need to add KEY_WOW64_64KEY flag when opening the registry to access the 64bit-part.

So if you use 32bit Lazarus you might end up with only the 32bit programs if you're not careful.

You made me think =) and I broke my head on how to make playing here and there.
that's what happened, but did not see ...
Code: Pascal  [Select][+][-]
  1. with MyRegistry do
  2.         begin
  3.         RootKey:=HKEY_LOCAL_MACHINE;
  4.         OpenKeyReadOnly('Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\');
  5.         GetKeyNames(MyList);
  6.         CloseKey;
  7.         for i:=0 to MyList.Count-1 do
  8.            begin
  9.            RootKey:=HKEY_LOCAL_MACHINE;
  10.            OpenKeyReadOnly('Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\'+
  11.            MyList[i]);
  12.            Str:=ReadString('DisplayName');
  13.            if Str<>'' then
  14.        //    Memo1.Lines.Add(SysToUTF8(ReadString('DisplayName')));
  15.            MyList2.Add(ReadString('DisplayName'));
  16.            CloseKey;
  17.            end;
  18.  
  19.         RootKey:=HKEY_LOCAL_MACHINE;
  20.         OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Uninstall\');
  21.         GetKeyNames(MyList);
  22.         CloseKey;
  23.         for i:=0 to MyList.Count-1 do
  24.            begin
  25.            RootKey:=HKEY_LOCAL_MACHINE;
  26.            OpenKeyReadOnly('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+
  27.            MyList[i]);
  28.            Str:=ReadString('DisplayName');
  29.            if Str<>'' then
  30.        //    Memo1.Lines.Add(SysToUTF8(ReadString('DisplayName')));
  31.            MyList2.Add(ReadString('DisplayName'));
  32.            CloseKey;
  33.            end;
  34.           end;  

lainz

  • Hero Member
  • *****
  • Posts: 4741
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Getting the list of installed programs
« Reply #6 on: September 21, 2016, 06:09:35 pm »
Hi, I've played with that some time ago, but I've not added the code that search both 32 and 64 bits, but you can look at my code here:
http://forum.lazarus-ide.org/index.php/topic,25292.msg153366.html#msg153366

Edit: If you compile it for 32 bit you need to change this line:

Code: Pascal  [Select][+][-]
  1. InstallDate := reg.ReadString('InstallDate');
  2.  

To

Code: Pascal  [Select][+][-]
  1. try
  2.   InstallDate := reg.ReadString('InstallDate');
  3. except
  4.   InstallDate := '';
  5. end;

At least it prevents the crash for me now. If other setting can't be read do the same try..except.
« Last Edit: September 21, 2016, 06:39:31 pm by lainz »

mrkaban

  • Jr. Member
  • **
  • Posts: 60
    • КонтинентСвободы
Re: Getting the list of installed programs
« Reply #7 on: September 22, 2016, 04:15:45 pm »
Hi, I've played with that some time ago, but I've not added the code that search both 32 and 64 bits, but you can look at my code here:
http://forum.lazarus-ide.org/index.php/topic,25292.msg153366.html#msg153366

Edit: If you compile it for 32 bit you need to change this line:

Code: Pascal  [Select][+][-]
  1. InstallDate := reg.ReadString('InstallDate');
  2.  

To

Code: Pascal  [Select][+][-]
  1. try
  2.   InstallDate := reg.ReadString('InstallDate');
  3. except
  4.   InstallDate := '';
  5. end;

At least it prevents the crash for me now. If other setting can't be read do the same try..except.
I reported on the link do not see the code ... maybe I do not understand?

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Getting the list of installed programs
« Reply #8 on: September 22, 2016, 04:20:12 pm »
I reported on the link do not see the code ... maybe I do not understand?
That's because lainz uses another URL for the forum (really annoying there are two).
You need to login there too or use this link:
http://forum.lazarus.freepascal.org/index.php/topic,25292.msg153366.html#msg153366

B.T.W. lainz, you already have the KEY_WOW64_64KEY in the comments there. So why didn't you expand the code to also retrieve the 64bit programs when compiled under 32bit? Would have been a small change.
Code: Pascal  [Select][+][-]
  1.   reg := TRegistry.Create(KEY_WRITE); // KEY_WRITE OR KEY_WOW64_64KEY

mrkaban

  • Jr. Member
  • **
  • Posts: 60
    • КонтинентСвободы
Re: Getting the list of installed programs
« Reply #9 on: September 22, 2016, 04:29:22 pm »
I reported on the link do not see the code ... maybe I do not understand?
That's because lainz uses another URL for the forum (really annoying there are two).
You need to login there too or use this link:
http://forum.lazarus.freepascal.org/index.php/topic,25292.msg153366.html#msg153366

B.T.W. lainz, you already have the KEY_WOW64_64KEY in the comments there. So why didn't you expand the code to also retrieve the 64bit programs when compiled under 32bit? Would have been a small change.
Code: Pascal  [Select][+][-]
  1.   reg := TRegistry.Create(KEY_WRITE); // KEY_WRITE OR KEY_WOW64_64KEY

Thank you all very much friends !!! everything worked out!

a special thank you note for a 32 and 64 bit registry branches with a list of programs.

That is direct a very big thank you to all forum users!

lainz

  • Hero Member
  • *****
  • Posts: 4741
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Getting the list of installed programs
« Reply #10 on: September 22, 2016, 08:29:17 pm »
I reported on the link do not see the code ... maybe I do not understand?
That's because lainz uses another URL for the forum (really annoying there are two).
You need to login there too or use this link:
http://forum.lazarus.freepascal.org/index.php/topic,25292.msg153366.html#msg153366

B.T.W. lainz, you already have the KEY_WOW64_64KEY in the comments there. So why didn't you expand the code to also retrieve the 64bit programs when compiled under 32bit? Would have been a small change.
Code: Pascal  [Select][+][-]
  1.   reg := TRegistry.Create(KEY_WRITE); // KEY_WRITE OR KEY_WOW64_64KEY

I don't know  :)

Well I can continue my program too for 32 and 64 bits.

- First do a pass with KEY_WRITE
- Then do a pass with KEY_WOW64_64KEY

or maybe..

- First do a pass with KEY_WOW64_32KEY
- Then do a pass with KEY_WOW64_64KEY

At least in Windows x64 the second approach works for both 32 and 64 bit applications, but I don't know under 32 bits Windows if both methods works the same, I need to get a 32 bit machine or virtual machine and test it really.

I suppose there is no KEW_WOW64_64KEY access under Windows of 32 bits and only works KEY_WRITE.
« Last Edit: September 22, 2016, 08:36:15 pm by lainz »

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Getting the list of installed programs
« Reply #11 on: September 22, 2016, 08:41:24 pm »
Yes, and actually Microsoft advises against directly accessing the Wow6432Node-key.

So on 32bit OS you can just access the same key.
On 64bit OS you would do both KEY_WOW64_64KEY and KEY_WOW64_32KEY on that same install key (with both a 64bit and 32bit program).

See https://msdn.microsoft.com/nl-nl/library/windows/desktop/aa384129(v=vs.85).aspx

Quote
Note  The Wow6432Node key is reserved. For compatibility, applications should not use this key directly.

lainz

  • Hero Member
  • *****
  • Posts: 4741
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Getting the list of installed programs
« Reply #12 on: September 22, 2016, 09:11:45 pm »
I ended up with the same MSDN link..

So we can do for 32 and 64 bit OS application:

Code: Pascal  [Select][+][-]
  1.   {$IFDEF Win32}
  2.   IterateRegistry(KEY_WRITE);
  3.   {$ENDIF}
  4.   {$IFDEF Win64}
  5.   IterateRegistry(KEY_WOW64_64KEY);
  6.   IterateRegistry(KEY_WOW64_32KEY);
  7.   {$ENDIF}

With "IterateRegistry" as a method somewhere.

rvk

  • Hero Member
  • *****
  • Posts: 6953
Re: Getting the list of installed programs
« Reply #13 on: September 22, 2016, 09:14:10 pm »
So we can do for 32 and 64 bit OS application:
...
With "IterateRegistry" as a method somewhere.
Yes, that should work.
Maybe with an addition of an extra field for the program if it's a 32bit or 64bit program. (That could be nice in the overview)

lainz

  • Hero Member
  • *****
  • Posts: 4741
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: Getting the list of installed programs
« Reply #14 on: September 22, 2016, 09:16:30 pm »
So we can do for 32 and 64 bit OS application:
...
With "IterateRegistry" as a method somewhere.
Yes, that should work.
Maybe with an addition of an extra field for the program if it's a 32bit or 64bit program. (That could be nice in the overview)

Thanks for that idea. I'm making the uninstaller from this code as base, I'll publish it on GitHub when ready.

 

TinyPortal © 2005-2018