Microsoft KB Archive/247985

From BetaArchive Wiki

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

  1. Create an MFC Appwizard EXE named OfficePath. In step 1 of AppWizard, select Dialog Based and click Finish.
  2. Click the Resources tab and open the IDD_OFFICEPATH_DIALOG dialog box.
  3. Remove the OK and Cancel Buttons on the dialog box.
  4. Add an EditBox to the dialog box and name it IDC_PROGID.
  5. Add two CommandButtons to the dialog box. Name the CommandButtons IDPATH and IDVERSION and set the captions to GetPath and GetVersion respectively.
  6. Start ClassWizard.
  7. Add a function handler to the BN_CLICKED message of each CommandButton.
  8. 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.
  9. Close the ClassWizard.
  10. 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);
  11. 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;
    
    }
  12. 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