?
Solved

How do i test wether MS Excel and MS Word are installed on the host machine OS (windows, office 97 / 2000) in D2006/win32 ?

Posted on 2006-05-18
6
Medium Priority
?
253 Views
Last Modified: 2010-04-05
A task given to me specifies that i should make a series of outprints based on a list of files. If the files are of other types than rtf, .doc and .xls, shellexecute is to be used to create outprints. If the file type is either .rtf or .doc, MS Word should be printing it by the use of OLE, if and only if MS Word is installed on the host machine. Else, shellexecute should be used so that Wordpad can start and print the document out instead. The same will probably apply to .doc files. Xls files will also be opened by shellexecute if Excel is not installed.

Do anyone know how to check if MS Word and MS Excel is installed? And can it be done using COM/OLE functions?

regards
classmate
0
Comment
Question by:classmate
  • 2
  • 2
  • 2
6 Comments
 
LVL 28

Expert Comment

by:2266180
ID: 16706637
Hi classmate,
you can rely on registry for this:

open the location: HKEY_CURRENT_USER\Software\Microsoft\Office\
if not failed, then iterate through keys 7.0 to 11.0 and check which one has Word\Options and in it the PROGRAMDIR key

using ole, you can use the trial and fail scheme: try to create an instance of the excel/word application. if not fail, it means that it exist and you can continue. if fail, then drop on the shellexecute. something like:

try
  create applications
  optional check if applications created correctly
  ok:=true;
except
  ok:=false;
end;
  if ok then use ole
         else shellexecute

Cheers!
0
 
LVL 2

Author Comment

by:classmate
ID: 16707095
hi ciuly!

In the OLE solution, how could i check if the applications were created correctly? Is it not guaranteed that an exception will be raised if word/excel is not installed?
Could the resulting object be set to nil?

In the registry approach, is the same solution applicable to excel?
0
 
LVL 28

Expert Comment

by:2266180
ID: 16707166
with the registry, the word solutino will not work for excel. I don't have a machine where excel is not installed in order to see if an "excel" key is created, but you could test and if excel is not installed and in registry no "excel" key appears (at the same level as word) then checking for existance of "excel" key will be sufficient.

regarding the ole, you could check for the object to be nil, any exceptions beeing thrown and if the var is empty. can't think of anything else. never had this issue before :)
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 26

Accepted Solution

by:
Russell Libby earned 2000 total points
ID: 16708632

This is from my source library that I use when dealing with Office applications, you may find it useful. Let me know if you have questions on usage.

Regards,
Russell

--

unit MSOffice;
////////////////////////////////////////////////////////////////////////////////
//
//   Unit        :  MSOffice
//   Author      :  rllibby
//   Date        :  11.01.2005
//   Description :  Class objects for determining if office applications are
//                  installed, as well as other useful information.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Include units
////////////////////////////////////////////////////////////////////////////////
uses
  Windows, SysUtils, Classes, ComObj, ActiveX;

////////////////////////////////////////////////////////////////////////////////
//   Microsoft Office application types
////////////////////////////////////////////////////////////////////////////////
type
  TOfficeApp        =  (oaAccess, oaExcel, oaInfoPath, oaOutlook, oaPowerPoint, oaPublisher, oaWord);

////////////////////////////////////////////////////////////////////////////////
//   Microsoft Office constants
////////////////////////////////////////////////////////////////////////////////
const
  Office_Programs:  Array [oaAccess..oaWord] of PChar =
                    (
                       'msaccess.exe',
                       'excel.exe',
                       'infopath.exe',
                       'outlook.exe',
                       'powerpnt.exe',
                       'mspub.exe',
                       'winword.exe'
                    );
  Office_Idents:    Array [oaAccess..oaWord] of PChar =
                    (
                       'Access.Application',
                       'Excel.Application',
                       'InfoPath.Application',
                       'Outlook.Application',
                       'PowerPoint.Application',
                       'Publisher.Application',
                       'Word.Application'
                    );

////////////////////////////////////////////////////////////////////////////////
//   MS Office Application objects
////////////////////////////////////////////////////////////////////////////////
type
  // Forward class
  TMSOffice         =  class;
  // MSOfficeApp
  TMSOfficeApp      =  class(TObject)
  private
     // Private declarations
     FApp:          TOfficeApp;
     FValid:        Boolean;
     FFile:         String;
     FVersion:      String;
  protected
     // Protected declarations
     function       GetProgrammaticID: String;
  public
     // Public declarations
     constructor    Create(Parent: TMSOffice; App: TOfficeApp);
     destructor     Destroy; override;
     function       CreateObject(out OleObject: OleVariant): Boolean;
     property       AppType: TOfficeApp read FApp;
     property       FileName: String read FFile;
     property       ProgrammaticID: String read GetProgrammaticID;
     property       Valid: Boolean read FValid;
     property       Version: String read FVersion;
  end;
  // TMSOffice
  TMSOffice         =  class(TObject)
  private
     // Private declarations
     FPath:         String;
     FVersion:      String;
     FApps:         Array [oaAccess..oaWord] of TMSOfficeApp;
     function       IsNumeric(Value: PChar): Boolean;
  protected
     // Protected declararations
     function       GetOfficeApp(Index: TOfficeApp): TMSOfficeApp;
     function       GetInstalled(Index: TOfficeApp): Boolean;
     function       GetValid: Boolean;
     procedure      EnumVersionKeys(Key: HKEY; List: TStrings);
     procedure      Load;
  public
     // Public declarations
     constructor    Create;
     destructor     Destroy; override;
     property       Installed[Index: TOfficeApp]: Boolean read GetInstalled;
     property       OfficeApp[Index: TOfficeApp]: TMSOfficeApp read GetOfficeApp;
     property       Path: String read FPath;
     property       Valid: Boolean read GetValid;
     property       Version: String read FVersion;
  end;

////////////////////////////////////////////////////////////////////////////////
//   Utility functions
////////////////////////////////////////////////////////////////////////////////
function   FloatSort(List: TStringList; Index1, Index2: Integer): Integer;
function   PathExists(Path: String): Boolean;
function   GetInstallPath(Key: HKEY; SubKey: String; out Path: String): Boolean;

implementation

////////////////////////////////////////////////////////////////////////////////
//   TMSOfficeApp
////////////////////////////////////////////////////////////////////////////////
function TMSOfficeApp.CreateObject(out OleObject: OleVariant): Boolean;
var  pvDisp:        IDispatch;
begin

  // Set out parameter
  OleObject:=Unassigned;

  // Attempt to create instance of object (IDispatch)
  if (CoCreateInstance(ProgIDToClassID(ClassName), nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IDispatch, pvDisp) = S_OK) then
  begin
     // Resource protection
     try
        // Set out parameter
        OleObject:=pvDisp;
        // Success
        result:=True;
     finally
        // Release local interface
        pvDisp:=nil;
     end;
  end
  else
     // Failed to instantiate
     result:=False;

end;

function TMSOfficeApp.GetProgrammaticID: String;
begin

  // Return the programmtic ID for the office application
  result:=Office_Idents[FApp];

end;

constructor TMSOfficeApp.Create(Parent: TMSOffice; App: TOfficeApp);
begin

  // Perform inherited
  inherited Create;

  // Set properties
  FApp:=App;
  FValid:=Parent.Installed[App];
  FFile:=Parent.Path+'\'+Office_Programs[App];
  FVersion:=Parent.Version;

end;

destructor TMSOfficeApp.Destroy;
begin

  // Perform inherited
  inherited Destroy;

end;

////////////////////////////////////////////////////////////////////////////////
//   TMSOffice
////////////////////////////////////////////////////////////////////////////////
function TMSOffice.GetOfficeApp(Index: TOfficeApp): TMSOfficeApp;
begin

  // Check the app at the given index
  if (FApps[Index] = nil) then
  begin
     // Need to create the object
     FApps[Index]:=TMSOfficeApp.Create(Self, Index);
  end;

  // Return the requested office app
  result:=FApps[Index]

end;

function TMSOffice.GetInstalled(Index: TOfficeApp): Boolean;
var  hkApp:         HKEY;
begin

  // Check Office to start with
  if GetValid then
  begin
     // Determine if the office application specified by index is actually installed
     if FileExists(FPath+'\'+Office_Programs[Index]) then
     begin
        // Ensure the programmatic ID can be located in the registry
        if (RegOpenKeyEx(HKEY_CLASSES_ROOT, Office_Idents[Index], 0, KEY_READ, hkApp) = ERROR_SUCCESS) then
        begin
           // Close the key
           RegCloseKey(hkApp);
           // Success
           result:=True;
        end
        else
           // Programmtic ID does not exist
           result:=False;
     end
     else
        // Program does not exist
        result:=False;
  end
  else
     // Office is not installed
     result:=False;

end;

function TMSOffice.GetValid: Boolean;
begin

  // Determine if the office object is valid
  result:=(Length(FVersion) > 0) and PathExists(FPath);

end;

procedure TMSOffice.EnumVersionKeys(Key: HKEY; List: TStrings);
var  lpszBuffer:    Array [0..4095] of Char;
     dwEnum:        Integer;
     dwIndex:       Integer;
begin

  // Check list
  if Assigned(List) then
  begin
     // Set enumerator start
     dwIndex:=0;
     // Seed the sub key enumerator
     dwEnum:=RegEnumKey(Key, dwIndex, @lpszBuffer, SizeOf(lpszBuffer));
     // Lock the list
     List.BeginUpdate;
     // Resource protection
     try
        // Clear the list
        List.Clear;
        // Iterate the keys
        while (dwEnum = ERROR_SUCCESS) do
        begin
           // Check numeric, add to list if version key
           if IsNumeric(@lpszBuffer) then List.Add(lpszBuffer);
           // Next item
           Inc(dwIndex);
           // Iterate next
           dwEnum:=RegEnumKey(Key, dwIndex, @lpszBuffer, SizeOf(lpszBuffer));
        end;
     finally
        // Unlock the list
        List.EndUpdate;
     end;
  end;

end;

procedure TMSOffice.Load;
var  listKeys:      TStringList;
     dwIndex:       Integer;
     hkOffice:      HKEY;
begin

  // Attempt to open the office key
  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Office', 0, KEY_READ, hkOffice) = ERROR_SUCCESS) then
  begin
     // Resource protection
     try
        // Create a list for key enumeration
        listKeys:=TStringList.Create;
        // Resource protection
        try
           // Now we need to find the most current version of office installed
           EnumVersionKeys(hkOffice, listKeys);
           // Check the count
           if (listKeys.Count > 0) then
           begin
              // Sort the list by version number
              listKeys.CustomSort(FloatSort);
              // Now walk the versions to determine the most current (valid) installation
              for dwIndex:=0 to Pred(listKeys.Count) do
              begin
                 // Check the install path, break once we find a valid one
                 if GetInstallPath(hkOffice, listKeys[dwIndex], FPath) then
                 begin
                    // Set the version number
                    FVersion:=listKeys[dwIndex];
                    // Done processing
                    break;
                 end;
              end;
           end;
        finally
           // Free the list
           FreeAndNil(listKeys);
        end;
     finally
        // Close the key
        RegCloseKey(hkOffice);
     end;
  end;

end;

function TMSOffice.IsNumeric(Value: PChar): Boolean;
begin

  // Set default result
  result:=True;

  // Walk the null terminated string
  while (Value^ > #0) do
  begin
     // Check char value
     if not(Value^ in ['.', '0'..'9']) then
     begin
        // Failure
        result:=False;
        // Done processing
        break;
     end;
     // Next char
     Inc(Value);
  end;

end;

constructor TMSOffice.Create;
begin

  // Perform inherited
  inherited Create;

  // Set starting defaults
  ZeroMemory(@FApps, SizeOf(FApps));
  SetLength(FPath, 0);
  SetLength(FVersion, 0);

  // Load
  Load;

end;

destructor TMSOffice.Destroy;
var  oaIndex:       TOfficeApp;
begin

  // Resource protection
  try
     // Cleanup
     for oaIndex:=oaAccess to oaWord do
     begin
        // Check application assignment
        if Assigned(FApps[oaIndex]) then
        begin
           // Free and nil the application
           FreeAndNil(FApps[oaIndex]);
        end;
     end;
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

////////////////////////////////////////////////////////////////////////////////
//   Utility functions
////////////////////////////////////////////////////////////////////////////////
function GetInstallPath(Key: HKEY; SubKey: String; out Path: String): Boolean;
var  hkVersion:     HKEY;
     lpszPath:      Array [0..MAX_PATH] of Char;
     dwPath:        DWORD;
begin

  // Attempt to open the version sub key
  if (RegOpenKeyEx(Key, PChar(SubKey+'\Common\InstallRoot'), 0, KEY_READ, hkVersion) = ERROR_SUCCESS) then
  begin
     // Resource protection
     try
        // Set buffer size
        dwPath:=SizeOf(lpszPath);
        // Query for the value
        if (RegQueryValueEx(hkVersion, 'Path', nil, nil, @lpszPath, @dwPath) = ERROR_SUCCESS) then
        begin
           // Check path
           if PathExists(lpszPath) then
           begin
              // Set out parameter
              Path:=ExcludeTrailingBackslash(lpszPath);
              // Success
              result:=True;
           end
           else
              // Directory does not exist
              result:=False;
        end
        else
           // Value does not exist
           result:=False;
     finally
        // Close the key
        RegCloseKey(hkVersion);
     end;
  end
  else
     // Not a valid key
     result:=False;

end;

function PathExists(Path: String): Boolean;
var  dwAttr:        DWORD;
begin

  // Get the attributes for the path
  dwAttr:=GetFileAttributes(PChar(ExcludeTrailingBackslash(Path)));

  // Check attributes
  result:=((dwAttr <> DWORD(-1)) and ((dwAttr and FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY));

end;

function FloatSort(List: TStringList; Index1, Index2: Integer): Integer;
begin

  // Exception trap
  try
     // Compare the values and return the difference
     result:=Trunc(StrToFloat(List[Index2])-StrToFloat(List[Index1]));
  except
     // Can't compare
     result:=0;
  end;

end;

end.


0
 
LVL 2

Author Comment

by:classmate
ID: 16708692
Hi Rllibby,

Thanks!

I'll spend some time digging into it during next week or perhaps tomorrow.


0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 16708949

No problem...

One slight correction for the CreateObject implementation:

function TMSOfficeApp.CreateObject(out OleObject: OleVariant): Boolean;
var  pvDisp:        IDispatch;
begin

  // Set out parameter
  OleObject:=Unassigned;

  // Attempt to create instance of object (IDispatch)
  if (CoCreateInstance(ProgIDToClassID(GetProgrammaticID), nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IDispatch, pvDisp) = S_OK) then
  begin
     // Resource protection
     try
        // Set out parameter
        OleObject:=pvDisp;
        // Success
        result:=True;
     finally
        // Release local interface
        pvDisp:=nil;
     end;
  end
  else
     // Failed to instantiate
     result:=False;

end;

I am also providing some sample code to help when you get around to this:
-----
var  msoOffice:     TMSOffice;
     msoaApp:       TMSOfficeApp;
     ovWord:        OleVariant;
begin

  // Create office wrapper
  msoOffice:=TMSOffice.Create;

  // Resource protection
  try
     // Check for valid path
     if not(msoOffice.Valid) then
        // Unable to detect an install
        ShowMessage('Unable to detect any office applications!')
     else
     begin
        // Determine if word can be detected (can also do the same thing for excel, access, etc...
        if not(msoOffice.Installed[oaWord]) then
           // Unable to find an installed version of app
           ShowMessage('Unable to detect MS Word!')
        else
        begin
           // Create a wrapper around the office application (**DO NOT MANUALLY FREE**)
           msoaApp:=msoOffice.OfficeApp[oaWord];
           // Show path to word
           ShowMessage(msoaApp.FileName);
           // Attempt to create an instance of the ole server
           if msoaApp.CreateObject(ovWord) then
           begin
              // Created instance, now show it
              ovWord.Visible:=True;
              // Release COM reference
              ovWord:=Unassigned;
           end
           else
              // Unable to create instance
              ShowMessage('Failed to create instance!');
        end;
     end;
  finally
     msoOffice.Free;
  end;

end;


0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Whether it be Exchange Server Crash Issues, Dirty Shutdown Errors or Failed to mount error, Stellar Phoenix Mailbox Exchange Recovery has always got your back. With the help of its easy to understand user interface and 3 simple steps recovery proced…
Suggested Courses
Course of the Month15 days, 8 hours left to enroll

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question