By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
426,107 Members | 1,323 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 426,107 IT Pros & Developers. It's quick & easy.

Search the registry

Expert 100+
P: 1,430
I am truing to search the registry to find which proofing languages are available for MS Office

Here are what appear to be the Registry entries. The bit after the 3 dots is the Default Value. The second entry translates as Georgian.

In addition to those languages, I have Mongolian installed, but there is no proofing available for this language

So I'm guessing that the only fixed bits we know are
"Installed Packages"
"Microsoft Office Proofing Tools"
and a language either in brackets or after a dash

I have no idea if the registry can be searched on so little information as I have a feeling that you need to supply the complete key, which obviously will vary depending on the version of Office.

Is it possible?


Jan 29 '18 #1
Share this Question
Share on Google+
12 Replies

Expert Mod 15k+
P: 31,419
Hi Phil.

Exactly what you need to do regarding this particular part of the Registry I can't really help with. However, I do have some code that reads the Registry.

Now I look at it, the code I was thinking of was actually code to traverse through the local domain's Active Directory. Not so much use :-(

Nevertheless, having almost promised you something I've looked at what I have and will see if I can knock something up for you that traverses through the keys from a specified start point and lists all the key and value names within. That should be enough to build on to include your own particular logic.
Jan 29 '18 #2

Expert 100+
P: 1,430
That sounds brilliant. I look forward to seeing what you come up with.

Please don't go to too much trouble though as time is valuable to you.

Jan 30 '18 #3

Expert Mod 15k+
P: 31,419
Hi Phil.

This took a while and a number of failures and complete crashes of Excel before I could get it right. I chose to use Excel as I didn't want to risk crashing or corrupting any existing databases and new spreadsheets are much easier to get started with ;-)

It returns a list of all Subkeys of a specified Registry Key. The returned value is a string including all the values separated by "\" characters. Why those? Because they can hardly be used within a name as they're used for specifying the structure itself of a Key.

You can be sure I'll be adding this to my existing modOS modules in all of my projects from now on.
Expand|Select|Wrap|Line Numbers
  1. Option Explicit
  3. 'Windows API Variable Prefixes
  4. 'cb = Count of Bytes (32-bit)
  5. 'w  = Word (16-bit)
  6. 'dw = Double Word (32-bit)
  7. 'lp = Long Pointer (32-bit)
  8. 'b  = Boolean (32-bit)
  9. 'h  = Handle (32-bit)
  10. 'ul = Unsigned Long (32-bit)
  12. Public Const conHKCR = &H80000000
  13. Public Const conHKCU = &H80000001
  14. Public Const conHKLM = &H80000002
  15. Public Const conHKU = &H80000003
  16. Public Const conStandardRightsAll = &H1F0000
  17. Public Const conReadControl = &H20000
  18. Public Const conStandardRightsRead = (conReadControl)
  19. Public Const conRegSz = 1
  20. Public Const conOK = 0&
  21. Public Const conKeyQueryValue = &H1
  22. Public Const conKeySetValue = &H2
  23. Public Const conKeyCreateLink = &H20
  24. Public Const conKeyCreateSubKey = &H4
  25. Public Const conKeyEnumerateSubKeys = &H8
  26. Public Const conKeyNotify = &H10
  27. Public Const conSynchronise = &H100000
  28. Public Const conRegOptionNonVolatile = 0
  29. Public Const conKeyAllAccess = ((conStandardRightsAll _
  30.                               Or conKeyQueryValue _
  31.                               Or conKeyCreateSubKey _
  32.                               Or conKeyEnumerateSubKeys _
  33.                               Or conKeyNotify _
  34.                               Or conKeyCreateLink) _
  35.                             And (Not conSynchronise))
  36. Public Const conKeyRead = ((conReadControl _
  37.                          Or conKeyQueryValue _
  38.                          Or conKeyEnumerateSubKeys _
  39.                          Or conKeyNotify) _
  40.                        And (Not conSynchronise))
  42. Private Type typFileTime
  43.     lngLoDT As Long
  44.     lngHiDT As Long
  45. End Type
  47. Private Declare Function RegOpenKeyEx Lib "advapi32.dll" _
  48.     Alias "RegOpenKeyExA" (ByVal hKey As Long, _
  49.                            ByVal lpSubKey As String, _
  50.                            ByVal ulOptions As Long, _
  51.                            ByVal samDesired As Long, _
  52.                            phkResult As Long) As Long
  53. Private Declare Function RegCloseKey Lib "advapi32.dll" _
  54.                              (ByVal hKey As Long) As Long
  55. Private Declare Function RegQueryValueExStr Lib "advapi32.dll" _
  56.     Alias "RegQueryValueExA" (ByVal hKey As Long, _
  57.                               ByVal lpValueName As String, _
  58.                               ByVal lpReserved As Long, _
  59.                               lpType As Long, _
  60.                               ByVal lpData As String, _
  61.                               lpcbData As Long) As Long
  62. Private Declare Function RegEnumKeyEx Lib "advapi32.dll" _
  63.     Alias "RegEnumKeyExA" (ByVal hKey As Long, _
  64.                            ByVal dwIndex As Long, _
  65.                            ByVal lpName As String, _
  66.                            ByRef lpcName As Long, _
  67.                            ByVal lpReserved As Long, _
  68.                            ByVal lpClass As String, _
  69.                            ByRef lpcClass As Long, _
  70.                            ByRef lpftLastWriteTime As typFileTime) As Long
  72. Public Function RegEnum(ByVal lngHive As Long, ByVal strKey As String) As String
  73.     Dim strName As String, strClass As String, strList As String
  74.     Dim lngRet As Long, lngName As Long, lngClass As Long, lngHKey As Long
  75.     Dim lngType As Long, lngIdx As Long
  76.     Dim ftLastWrite As typFileTime
  78.     RegEnum = ""
  79.     strKey = strKey & Chr(0)
  80.     lngRet = RegOpenKeyEx(lngHive, strKey, 0, conKeyRead, lngHKey)
  81.     If lngRet <> conOK Then Exit Function
  82.     'Create buffer to store value
  83.     strName = Space(255)
  84.     strClass = Space(255)
  85.     Do While lngRet = 0
  86.         lngName = 255
  87.         lngClass = 255
  88.         lngRet = RegEnumKeyEx(hKey:=lngHKey _
  89.                             , dwIndex:=lngIdx _
  90.                             , lpName:=strName _
  91.                             , lpcName:=lngName _
  92.                             , lpReserved:=ByVal 0& _
  93.                             , lpClass:=strClass _
  94.                             , lpcClass:=lngClass _
  95.                             , lpftLastWriteTime:=ftLastWrite)
  96.         If lngName < 255 _
  97.         And lngClass < 255 Then _
  98.             strList = strList & "\" & Left(strName, lngName)
  99.         lngIdx = lngIdx + 1
  100.     Loop
  101.     'Close key
  102.     Call RegCloseKey(lngHKey)
  103.     RegEnum = Mid(strList, 2)
  104. End Function
  106. Public Function RegRead(ByVal lngHive As Long, _
  107.                         ByVal strKey As String, _
  108.                         ByVal strValue As String) As Variant
  109.     Dim intIdx As Integer
  110.     Dim strWork As String
  111.     Dim lngRet As Long, cbLen As Long, lngHKey As Long, lngType As Long
  113.     RegRead = Null
  114.     strKey = strKey & Chr(0)
  115.     lngRet = RegOpenKeyEx(lngHive, strKey, 0, conKeyRead, lngHKey)
  116.     If lngRet = conOK Then
  117.         'Create buffer to store value
  118.         strWork = Space(255)
  119.         cbLen = 255
  120.         lngRet = RegQueryValueExStr(lngHKey, _
  121.                                     strValue, _
  122.                                     0&, _
  123.                                     lngType, _
  124.                                     strWork, _
  125.                                     cbLen)
  126.         RegRead = Left(strWork, cbLen - 1)
  127.         If Len(RegRead) = 254 Then RegRead = Null
  128.         'Close key
  129.         Call RegCloseKey(lngHKey)
  130.     End If
  131. End Function
Feb 2 '18 #4

Expert 100+
P: 1,430
That looks interesting, but never having heard of hives, I am as a complete loss to know what values to feed in.

I would be very grateful for a few examples.

Feb 2 '18 #5

Expert 100+
P: 1,430
The text file in the earlier post gives all the information I have.
The search routine needs to run on any computer, so I'm guessing that the beginning of the key will start with
Expand|Select|Wrap|Line Numbers
  1. Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\
Then presumably the version of Office will appear somewhere in the string.

Again a guess that
Expand|Select|Wrap|Line Numbers
  1. Common\InstalledPackages
will appear somewhere and the default value we are looking for could be any of these
Expand|Select|Wrap|Line Numbers
  1. Microsoft Office Proofing Tools 2016 - English
  2. Microsoft Office Proofing Tools 2016 - ქართული
  3. Microsoft Office Proofing Tools (German) 2016
  4. Microsoft Office Proofing Tools (English) 2016
  5. Microsoft Office Proofing Tools (Russian) 2016
So it just adds to the fun that on my PC anyway, there are 2 different output formats

Actually, I have just looked again, and instead of finding the Default Value, the "ProductLanguage" is consistent and what is much better ties up with the language codes I am using

So we just want the value of "ProductLanguage"

Interestingly, the English dictionary appears to spell check French & Spanish as well, but not German.


Feb 2 '18 #6

Expert Mod 15k+
P: 31,419
If you've ever opened your Registry Editor (Generally RegEdit.Exe) you'll have seen that the registry, as a whole, is broken up into separate starting sections called hives. You may be familiar with their names; I've included with each, where I have one, the constant defined in the module to use for it :
  4. conHKU (3) - HKEY_USERS
HKEY stands for Hive Key.

These all start in different places; some are stored in different files entirely. As far as the Registry is concerned though, they present simply as separate Hives within it. Within each Hive is a structure of Keys. All Subkeys are also Keys. Keys hold no information per se; they only hold other Keys and Values. Values are where, in the Registry, all actual information is stored. Their position within the Hive and Key structure is obviously critical but they are the only places where actual data is found. Values come in various shapes and sizes. Zero-terminated strings; Binarys; DWORD(32-bit); QWORD(64-bit); Multi-Strings & Expandable Strings. This is important as the code provided only handles Zero-terminated String Values.

NB. Enumerating the Keys does just that. It enumerates the Keys. Only. Values are not included in this code. You have to know which Values are expected and that they match the type we've coded for. Most simple text does, but always beware of strings being saved as Unicode as opposed to ANSI ASCII.

In my earlier code you'll notice there are constants that can be used to represent these Hives. These are used when calling the procedure as illustrated below. I understand from your latest post that the Hive you're interested in is HKEY_LOCAL_MACHINE so we can use the constant conHKLM. I also noticed that the Key you refer to isn't even present on my machine. It goes as far as HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\Commo n but doesn't include a Key called InstalledPackages within that. That's a problem for another day.

So, assuming you have a machine that includes HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\Commo n\InstalledPackages, the following code will show the Subkeys within that Key. Bear in mind it won't show Values; only Keys.

I can't tell from your post, and obviously am unable to check on my own machine, whether what you're looking for are Keys or Values. So, I'll show how to list the Keys and you can tell me how you get on with it when you try on your system.
Expand|Select|Wrap|Line Numbers
  1. Dim strVal As String
  2. Dim varItem As Variant
  4. strVal = "SOFTWARE\Microsoft\Office\Common\InstalledPackages")
  5. For Each varItem In Split(RegEnum(conHKLM, strVal), "\")
  6.     Debug.Print varItem
  7. Next varItem
If there Key doesn't exist, or it has no Subkeys (regardless of Values), then it will simply show nothing.
Feb 2 '18 #7

Expert 100+
P: 1,430
Thanks for the explanation, it is a little clearer now.

Obviously you have no language packs installed hence your failure to find "InstalledPackages" on your machine.

The only portion of the initial key we have in common is
Your Machine then goes on to "Common\" whilst my machine goes on yo
"ClickToRun\REGISTRY\MACHINE\Software\Wow6432Node\ Microsoft\Office\16.0\Common\"

However, suppose you were looking for Access\Report Formats and you wanted to find the value of "Rich Text Format" - I'm guessing we both have these in our registry, how would you do that?

The problem being that we both have the same initial key
"SOFTWARE\Microsoft\Office\", and we both probably have the same end Key
"Access\Report Formats"
and both of us definitely have totally different intermediate keys.

Thanks as ever

Feb 3 '18 #8

Expert Mod 15k+
P: 31,419
Hi Phil.

However, suppose you were looking for Access\Report Formats and you wanted to find the value of "Rich Text Format" - I'm guessing we both have these in our registry, how would you do that?
That really depends on whether we're talking about a value or a Value. Can you specify exactly where it's found on your machine? At least one of them.
Feb 3 '18 #9

Expert 100+
P: 1,430

The key is
"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Of fice\ClickToRun\REGISTRY\MACHINE\Software\Wow6432N ode\Microsoft\Office\16.0\Access\Report Formats"

Name: Rich Text Format

Type: REG_SZ

Data: rtf,SOA_RptToRTF,Rich Text Format,Rich Text Format (*.rtf),0


Feb 3 '18 #10

Expert Mod 15k+
P: 31,419
That's a Value then, clearly. Let me see what I can do to create a routine for returning a list of Values within a specified Key.

Remember, terminology is critical for clarity. Without clarity we end up going off on tangents similar to the earlier work. That said - I suspect that would have been necessary at some point anyway. Now we all know that we are dealing only with Hives, Keys and Values we should be able to keep everything clear going forwards.

I'll see what I can find to allow us to enumerate the Values in a Key.
Feb 3 '18 #11

Expert 100+
P: 1,430
Sorry about lake of clarity. Although I have looked at the registry from time to time, and very rarely modified Value, as you can see I am a complete amateur in this field (and, judging by the number of recent questions posed, also in the subject of Access databases)

Incidentally, I don't understand your comment about Value & value

Feb 3 '18 #12

Expert Mod 15k+
P: 31,419
Ah. I guessed not. Let me try to clarify.
value - Standard word in the Enlish language which means exactly what you take it to mean.
Value - With a capital V in the context of the Registry, is a container called a Value that the Registry stores data within.
Almost all of the Values contain values.

It may be most easily understood by using a picture of my own Registry and saying all the items on the left are Hives, Keys and Subkeys (which are themselves also Keys), while all the items on the right are Values.

The Hives are those directly under Computer in the picture and everything else on the left is a Key. Keys (and Hives) are shown with a yellow folder icon.
The Values are the only items that can contain data as such. Some Values here are of type REG_SZ (Registry String Zero terminated) while others are REG_DWORD (Registry Double Word).

Just to be absolutely clear the Value called iTunesDefault has a value of 0. The Value called InstallDir has a value of "C:\Program Files\iTunes\".

By the way, in case it helps, and also because I want as many people as possible to be aware of it, I've just written an article (VBA to C Crossover) that explains how to work with the sort of procedures such as are found in ADVAPI32.DLL - which are designed to be used by c-type languages - even from a VB type language such as VBA.
Attached Images
File Type: jpg 2018-02-03_21-43-00.jpg (82.9 KB, 231 views)
Feb 3 '18 #13

Post your reply

Sign in to post your reply or Sign up for a free account.