0

I need to know if there is any way to detect in a client PC (Windows) there any PDF reader (Adobe Reader, Foxit Reader, ...), using VB6 and. NET (C #).

I can not do by reading the Windows registry, because the user may not have permissions to read it.

Thank you.

andres descalzo
  • 14,887
  • 13
  • 64
  • 115
  • 2
    If the user can open a file with a pdf reader by double-clicking it, then s/he can also read the registry entries that tell the shell what to do when the file with that extension is double-clicked. The shell operates with the same security token as the user, since it is just a process spawned by the user. If you get a security error while looking for a .pdf registration in the registry, ignore it and continue your search algorithm. If at the end you've only encountered security errors, it means there is no pdf viewer available to that user. – David Gladfelter Feb 12 '10 at 18:02
  • Agreed, a restricted user will have read-only rights to HKCR\.pdf. If she wouldn't, she couldn't start a PDF reader. – Hans Passant Feb 12 '10 at 19:00
  • Ok, I go testing the responses sent to me reply then how I worked best. I also see the comment by @David Gladfelter – andres descalzo Feb 13 '10 at 22:03

4 Answers4

2

Create a temporary file with an extension of ".pdf", and then use FindExectuable for your temporary file. Note that even though only the extension really matters, FindExecutable still requires a real file, not just a name with the right extension.

Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
2

A sample based on Jerry Coffin's suggestion to use FindExecutable (based on this article):

Private Declare Function FindExecutable Lib "shell32.dll" _
  Alias "FindExecutableA"  ( _
  ByVal lpFile As String, _
  ByVal lpDirectory As String, _
  ByVal lpResult As String) As Long 

Private Declare Function lstrlen Lib "kernel32.dll" _
  Alias "lstrlenA" ( _
  ByVal lpString As Any) As Long

' FindExecutable Constants
Private Const ERROR_FILE_NOT_FOUND = 2&
Private Const ERROR_PATH_NOT_FOUND = 3&
Private Const ERROR_BAD_FORMAT = 11&

Private Sub Command1_Click()
  Dim Retval As Long, buffer As String

  ' init buffer 
  buffer = Space(256)

  Retval = FindExecutable("c:\windows\media\tada.wav", "", buffer)

  Select Case Retval
    Case 0
      Debug.Print "Not enough memory to execute this method." 
    Case 31
      Debug.Print "No file association found."
    Case ERROR_FILE_NOT_FOUND
      Debug.Print "File not found."
    Case ERROR_PATH_NOT_FOUND
      Debug.Print "Path not found."
    Case ERROR_BAD_FORMAT
      Debug.Print "The associated application is not a valid Win32 executable."
    Case Else
      Debug.Print "Associated application: " & Left$(buffer, lstrlen(buffer))
  End Select
End Sub
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
1

This VB routine will get the default executable for a file extension. If there is no executable then the user does not have a program configured to handle the extension.

Private Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" (ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As String) As Long

Function GetAssociation(ByVal Path As String, ByVal FileName As String) As String
   Dim Result As String
   Dim x As Long
   Dim lngLenBuff

   lngLenBuff = 256
   Result = String(lngLenBuff, vbNullChar)
   x = FindExecutable(FileName, Path, Result)
   GetAssociation = Left$(Result, InStr(Result, Chr$(0)) - 1) 'get string to left of the null'
End Function
jac
  • 9,666
  • 2
  • 34
  • 63
0

I know the question was for VB, but found a decent implementation of FindExecutable in C# here:

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace PaytonByrd {
public class Win32API
{
  [DllImport("shell32.dll", EntryPoint="FindExecutable")] 
  public static extern long FindExecutableA(
    string lpFile, string lpDirectory, StringBuilder lpResult);

  public static string FindExecutable(
    string pv_strFilename)
  {
    StringBuilder objResultBuffer = 
      new StringBuilder(1024);
    long lngResult = 0;

    lngResult = 
      FindExecutableA(pv_strFilename, 
        string.Empty, objResultBuffer);

    if(lngResult >= 32)
    {
        return objResultBuffer.ToString();
    }

    return string.Format(
      "Error: ({0})", lngResult);
  }
}}

Here's a usage example:

using System;
using System.Diagnostics;
using System.IO;
using PaytonByrd;

namespace CSharpFindExecutableTester
{
  class Class1
  {
    [STAThread]
    static void Main(string[] args)
    {
      foreach(string strFile in 
        Directory.GetFiles("c:\\"))
      {
        string strOutput = 
          string.Format(
            "{0} - Application: {1}",
            strFile, 
            Win32API.FindExecutable(
              strFile));

        Debug.WriteLine(strOutput);
      }
    }
  }
}
ProKiner
  • 697
  • 7
  • 12