Article ID: 247985
Article Last Modified on 6/30/2004
APPLIES TO
- Microsoft Excel 2000 Standard Edition
- Microsoft Visual C++ 5.0 Professional Edition
- Microsoft Visual C++ 6.0 Professional Edition
- Microsoft Access 97 Standard Edition
- Microsoft Excel 97 Standard Edition
- Microsoft Outlook 97 Standard Edition
- Microsoft PowerPoint 97 Standard Edition
- Microsoft Word 97 Standard Edition
- Microsoft Access 2000 Standard Edition
- Microsoft Outlook 2000 Standard Edition
- Microsoft PowerPoint 2000 Standard Edition
- Microsoft Word 2000 Standard Edition
- Microsoft Access 2002 Standard Edition
- Microsoft Excel 2002 Standard Edition
- Microsoft Outlook 2002 Standard Edition
- Microsoft PowerPoint 2002 Standard Edition
- Microsoft Word 2002 Standard Edition
This article was previously published under Q247985
SUMMARY
This article explains how you can examine the registry at run time to determine the installation path and version of an Office application.
MORE INFORMATION
Each Office application is associated with a version independent ProgID and a CLSID. You can examine the registry for keys containing a server's CLSID and ProgID to determine both the installation path and version of the server application.
The path to the server application can be found at:
HKEY_CLASSES_ROOT\CLSID\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx}\LocalServer32
where {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx} represents the the CLSID of the server.
Likewise, the version dependent ProgID for the registered version for the server application is located at:
HKEY_CLASSES_ROOT\sss.sss\CurVer
where sss.sss represents the version independent ProgID of the server.
Steps to Create Sample
- Create an MFC Appwizard EXE named OfficePath. In step 1 of AppWizard, select Dialog Based and click Finish.
- Click the Resources tab and open the IDD_OFFICEPATH_DIALOG dialog box.
- Remove the OK and Cancel Buttons on the dialog box.
- Add an EditBox to the dialog box and name it IDC_PROGID.
- Add two CommandButtons to the dialog box. Name the CommandButtons IDPATH and IDVERSION and set the captions to GetPath and GetVersion respectively.
- Start ClassWizard.
- Add a function handler to the BN_CLICKED message of each CommandButton.
- Create a member variable for the EditBox IDC_PROGID. Name the member variable m_ProgID and specify Control for the category and CEdit for the variable type.
- Close the ClassWizard.
In the OfficePathDlg.h file, add the following public member functions to the COfficePathDlg class:
static BOOL GetPath(LPOLESTR szApp, LPSTR szPath, ULONG cSize); static BOOL GetVersion(LPCTSTR szApp, LPSTR szVersion, ULONG cSize);
Add the following function definitions to OfficePathDlg.cpp:
void COfficePathDlg::OnPath() { LPOLESTR szwApp; char szLocation[255], szApp[50]; // Get ProgID from EditBox m_ProgID.GetWindowText(szApp, 50); if (strcmp(szApp,"") == 0) { MessageBox("Type ProgID in EditBox", "Error"); return; } // Find number ofcharacters to be allocated int len = strlen(szApp) + 1; // Use OLE Allocator to allocate memory szwApp = (LPOLESTR) CoTaskMemAlloc(len*2); if (szwApp == NULL) { MessageBox("Out of Memory", "Error"); return; } // AnsiToUnicode conversion if (0 == MultiByteToWideChar(CP_ACP, 0, szApp, len, szwApp, len)) { // Free Memory allocated to szwApp if conversion failed CoTaskMemFree(szwApp); szwApp = NULL; MessageBox("Error in Conversion", "Error"); return; } // Get Path to Application and display it if (!GetPath(szwApp, szLocation, 255)) MessageBox("Error Getting Path", "Error"); else MessageBox(szLocation, "Path"); } void COfficePathDlg::OnVersion() { CHAR szVersion[255], szApp[50]; // Get Version of Application m_ProgID.GetWindowText(szApp, 50); if (strcmp(szApp,"") == 0) { MessageBox("Type ProgID in EditBox", "Error"); return; } // Get Version and display it if (!GetVersion(szApp, szVersion, 255)) MessageBox("Error Getting Version", "Error"); else MessageBox(szVersion, "Version"); } BOOL COfficePathDlg::GetPath(LPOLESTR szApp, LPSTR szPath, ULONG cSize) { CLSID clsid; LPOLESTR pwszClsid; CHAR szKey[128]; CHAR szCLSID[60]; HKEY hKey; // szPath must be at least 255 char in size if (cSize < 255) return FALSE; // Get the CLSID using ProgID HRESULT hr = CLSIDFromProgID(szApp, &clsid); if (FAILED(hr)) { AfxMessageBox("Could not get CLSID from ProgID, Make sure ProgID is correct", MB_OK, 0); return FALSE; } // Convert CLSID to String hr = StringFromCLSID(clsid, &pwszClsid); if (FAILED(hr)) { AfxMessageBox("Could not convert CLSID to String", MB_OK, 0); return FALSE; } // Convert result to ANSI WideCharToMultiByte(CP_ACP, 0, pwszClsid, -1, szCLSID, 60, NULL, NULL); // Free memory used by StringFromCLSID CoTaskMemFree(pwszClsid); // Format Registry Key string wsprintf(szKey, "CLSID\\%s\\LocalServer32", szCLSID); // Open key to find path of application LONG lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_ALL_ACCESS, &hKey); if (lRet != ERROR_SUCCESS) { // If LocalServer32 does not work, try with LocalServer wsprintf(szKey, "CLSID\\%s\\LocalServer", szCLSID); lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_ALL_ACCESS, &hKey); if (lRet != ERROR_SUCCESS) { AfxMessageBox("No LocalServer Key found!!", MB_OK, 0); return FALSE; } } // Query value of key to get Path and close the key lRet = RegQueryValueEx(hKey, NULL, NULL, NULL, (BYTE*)szPath, &cSize); RegCloseKey(hKey); if (lRet != ERROR_SUCCESS) { AfxMessageBox("Error trying to query for path", MB_OK, 0); return FALSE; } // Strip off the '/Automation' switch from the path char *x = strrchr(szPath, '/'); if(0!= x) // If no /Automation switch on the path { int result = x - szPath; szPath[result] = '\0'; // If switch there, strip it } return TRUE; } BOOL COfficePathDlg::GetVersion(LPCTSTR szApp, LPSTR szVersion, ULONG cSize) { CHAR szKey[128], szValueName[128]; HKEY hKey, hKey1; wsprintf(szKey, "%s", szApp); LONG lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_ALL_ACCESS, &hKey); if (lRet != ERROR_SUCCESS) { // Word is registered, but no local server can be found!!! AfxMessageBox("Could not get CLSID from ProgID, Make sure ProgID is correct", MB_OK, 0); return FALSE; } wsprintf(szValueName, "%s", "CurVer"); lRet = RegOpenKeyEx(hKey, szValueName, 0, KEY_ALL_ACCESS, &hKey1); if (lRet != ERROR_SUCCESS) { // Excel is registered, but no local server can be found!!! return FALSE; } // Get the Version information lRet = RegQueryValueEx(hKey1, NULL, NULL, NULL, (BYTE*)szVersion, &cSize); // Close the registry keys RegCloseKey(hKey1); RegCloseKey(hKey); // Error while querying for value if (lRet != ERROR_SUCCESS) return FALSE; // At this point szVersion contains the ProgID followed by a number. // For example, Word 97 will return Word.Application.8 and Word 2000 will return Word.Application.9 // Store the version number char *x = strrchr(szVersion, '.'); szVersion[0] = *(x + 1); szVersion[1] = '\0'; if (strcmp(szVersion, "6") == 0) strcpy(szVersion, "Version 95"); else if (strcmp(szVersion, "8") == 0) strcpy(szVersion, "Version 97"); else if (strcmp(szVersion, "9") == 0) strcpy(szVersion, "Version 2000"); else if (strcmp(szVersion,”1”) == 0) strcpy(szVersion, “Version 2002”); else strcpy(szVersion, "Version unknown"); return TRUE; }
- Build the Project.
When you run the application, type the ProgID for an Office application in the edit box. Note: an example of a ProgID is Word.Application. Click the GetPath button to retrieve the path and click the GetVersion button to retrieve the registered version.
Additional Notes
If you have multiple versions of an Office application installed on your system, the version number corresponds to the application that is registered. In most cases, the registered version is the last version you ran.
If the server application is not installed, the calls to open its associated registry keys fail. You can use error handling in this situation to determine if the server application is installed.
REFERENCES
240794 How To Determine the Path for an Office Application
234788 How To Find the Installation Path of an Office 2000 Application
Additional query words: directory
Keywords: kbhowto kbregistry KB247985