2009-07-28 25 views
12

Tengo una aplicación VB6 que abre los archivos con su aplicación asociada mediante:¿Qué motivos pueden hacer que ShellExecute falle?

ShellExecute(0, "open", filename, params, vbNullString, vbNormalFocus) 

Esto funciona perfectamente.

Ahora tengo un cliente (que ejecuta XP con Adobe Reader) que no puede abrir ningún archivo PDF con el comando anterior. Pero el mismo archivo se abre sin ningún problema al hacer doble clic desde el Explorador de Windows. También probé la combinación de nombre de archivo/ruta en mi máquina para excluir ese tipo de problemas.

Estoy buscando alguna pista sobre lo que podría verificar para asegurarme de que ShellExecute esté funcionando. ¿O qué puede hacer que ShellExecute falle de esta manera?

+0

Tengo curiosidad de por qué está agregando vbNullString al nombre del archivo. ¿Alguna razón para eso? ¿Algún cambio si _no_ lo usa? –

+0

Creo que no es necesario agregar 'vbNullString' al final de sus cadenas. Sin embargo, si estoy equivocado, también deberá agregarlo al "Abrir". – Treb

+0

No es realmente necesario. Solo lo agregué algún día y ahora sigue ahí. Luego lo agregué debido a la documentación que decía que la función está tomando cadenas terminadas en nulo. – MicSim

Respuesta

9

¿Cuál es el valor de retorno de ShellExecute? Si es 0x0000001f (== 31, que significa SE_ERR_NOASSOC), de acuerdo con shellapi.h "No hay ninguna aplicación asociada con con la extensión de nombre de archivo dada.", lo que significa que de alguna manera se perdió el registro de la extensión de archivo .pdf. La reinstalación de Adobe Reader podría ayudar.

+0

Eso es lo extraño, sin embargo. ¿Por qué el PDF funcionaría en el escritorio pero no en un ShellExecute? Muy extraño. –

+1

Puede ser que Explorer use algo de vudú COM;) –

+2

Hay al menos dos formas en que windows usa para decidir qué aplicación llamar para qué extensión de archivo: las que son válidas para todos los usuarios en la máquina y las que son específicas del usuario. Tal vez el usuario jugueteó con las asociaciones de archivos PDF (Explorer: Opciones de carpeta - Tipos de archivos). – Treb

3

Eche un vistazo al valor de retorno de su llamada ShellExecute. Desde el MSDN:

Si la función tiene éxito, devuelve un valor mayor que 32. Si la función falla, devuelve un valor de error que indica la causa de la falla. El valor de retorno se emite como HINSTANCE para compatibilidad con versiones anteriores con aplicaciones de Windows de 16 bits. Sin embargo, no es un verdadero HINSTANCE. Se puede convertir solo en un int y en comparación con 32 o los siguientes códigos de error.

0: El sistema operativo no está en la memoria o en los recursos.

ERROR_FILE_NOT_FOUND: No se encontró el archivo especificado.

ERROR_PATH_NOT_FOUND: no se encontró la ruta especificada

(...)

+0

Voy a registrar este valor y luego sabré más. – MicSim

9

Además de Thomas de answer, aquí hay algunas constantes de Visual Basic 6 para posibles valores de retorno de ShellExecute, con posibles explicaciones (creo que originalmente los tomó de MSDN page, sección de valor de retorno). Un valor de retorno de 32 o menos significa que la llamada falló. El valor específico devuelto indica qué salió mal.

Const ERROR_BAD_FORMAT = 11& 
Const ERROR_FILE_NOT_FOUND = 2&   
Const ERROR_PATH_NOT_FOUND = 3&   ' The specified path was not found. ' 
Const SE_ERR_ACCESSDENIED = 5   ' The operating system denied access to the specified file. ' 
Const SE_ERR_ASSOCINCOMPLETE = 27  ' The file name association is incomplete or invalid. ' 
Const SE_ERR_DDEBUSY = 30    ' The Dynamic Data Exchange (DDE) transaction could not be completed because other DDE transactions were being processed. ' 
Const SE_ERR_DDEFAIL = 29    ' The DDE transaction failed. ' 
Const SE_ERR_DDETIMEOUT = 28    ' The DDE transaction could not be completed because the request timed out. ' 
Const SE_ERR_DLLNOTFOUND = 32   ' The specified dynamic-link library (DLL) was not found. ' 
Const SE_ERR_FNF = 2      ' The specified file was not found. ' 
Const SE_ERR_NOASSOC = 31    ' There is no application associated with the given file name extension. ' 
Const SE_ERR_OOM = 8      ' out of memory ' 
Const SE_ERR_PNF = 3      ' path not found ' 
Const SE_ERR_SHARE = 26     ' A sharing violation occurred. ' 
4

Usted tiene "abierta", como verbo, no hagas eso, utilice vbNullString como el verbo ("abierto" significa el verbo abierta, NULL significa el verbo predeterminado (Si el usuario no ha fijado una específica de manera predeterminada, el valor predeterminado es abierta, si no hay un verbo abierto para ese tipo de archivo, ShellExecute utiliza el primer verbo que encuentre))

+2

Esto parece ser una cosa extraña de hacer. Si un usuario ha cambiado el verbo predeterminado a "Editar" o "Imprimir", el resultado no será el deseado: ver el documento PDF. – Bob77

+0

Esa es su elección. Es mejor que usar un verbo que podría no existir. Si quieres lo mejor de ambos mundos, puedes verificar si el verbo abierto existe primero, y si no, usa NULL (pero de esta manera estás realmente atornillando a tu usuario ya que ellos configuraron un valor predeterminado y lo ignoraste) – Anders

+1

Además, la pregunta comienza con "Qué razones" y esta es una razón válida, así que no entiendo por qué me están votando. (He visto este problema en la naturaleza) – Anders

3

en lugar de utilizar ShellExecute a 'ejecutar' el archivo PDF, utilizo el API FindExecutable:

Private Const ERROR_FILE_NO_ASSOCIATION  As Long = 31 
Private Const ERROR_FILE_NOT_FOUND   As Long = 2 
Private Const ERROR_PATH_NOT_FOUND   As Long = 3 
Private Const ERROR_FILE_SUCCESS   As Long = 32 
Private Const ERROR_BAD_FORMAT    As Long = 11 

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


Private Sub OpenDocument(sFile as string, sPath as string) 
    Dim sResult As String 
    Dim lSuccess As Long, lPos as long 

    sResult = Space$(MAX_PATH) 
    lSuccess = FindExecutable(sFile, sPath), sResult) 
    Select Case lSuccess 
     Case ERROR_FILE_NO_ASSOCIATION 
      If Right$(sFile, 3) = "pdf" Then 
       MsgBox "You must have a PDF viewer such as Acrobat Reader to view pdf files." 
      Else 
       MsgBox "There is no registered program to open the selected file." & vbCrLf & sFile 
      End If 
     Case ERROR_FILE_NOT_FOUND: MsgBox "File not found: " & sFile 
     Case ERROR_PATH_NOT_FOUND: MsgBox "Path not found: " & sPath 
     Case ERROR_BAD_FORMAT:  MsgBox "Bad format." 
     Case Is >= ERROR_FILE_SUCCESS: 
      lPos = InStr(sResult, Chr$(0)) 
      If lPos Then sResult = Left$(sResult, lPos - 1) 
      Shell sResult & " " & sPath & sFile, True), vbMaximizedFocus 
    End Select 

End Sub 
+0

+1, interesante. Por curiosidad, ¿por qué decidiste FindExecutable en lugar de ShellExecute? Los códigos de error que recibes parecen muy similares, ¿es solo que tienes que hacer esos controles antes de intentar realmente iniciar el archivo? ¿Tuvo algunos problemas con ShellExecute que al usar FindExecutable lo ayudó a moverse? – Gavin

+0

FindExecutable hace el trabajo de encontrar el programa que está registrado para ejecutarse según una extensión de archivo determinada. ShellExecute es ideal para ejecutar y esperar la llamada (en lugar de solo Shell), pero parece utilizar un método de ejecución de fuerza más bruta que a veces resulta en un error. Usé http://vbnet.mvps.org/index.html?code/system/findexecutable.htm como mi fuente. Es un recurso fantástico para el uso de la API VB-6. –

1
  1. Desinstalar y reinstalar Acrobat Reader.
  2. En "Documentos y configuración", cambie el nombre de la carpeta "nombre de usuario" a "usernamex" (debe haber iniciado sesión con un usuario administrador diferente).
  3. Relogin como usuario y crea una nueva carpeta de "nombre de usuario" con un nuevo registro de usuario.
  4. Ahora debería funcionar.

Puede copiar archivos de la carpeta UsernameX a la nueva carpeta de nombre de usuario (de escritorio, documentos, etc.)

0

He aquí una función que traduce a los números de error de Windows para el texto. Puede usar el valor de retorno como parámetro y obtener un mensaje más amigable.

Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" _ 
    (ByVal dwFlags As Long, lpSource As Long, ByVal dwMessageId As Long, _ 
    ByVal dwLanguageId As Long, ByVal lpBuffer As String, _ 
    ByVal nSize As Long, ByVal Arguments As Any) As Long 

Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000 
Private Const FORMAT_MESSAGE_IGNORE_INSERTS = &H200 
Private Const MAX_PATH = 260 

Function TranslateDLLError(ByVal lngErrNum As Long) As String 
    Dim sRtrnCode As String * MAX_PATH 
    Dim lRet As Long 

    On Error GoTo errTranslateDLLError(

    sRtrnCode = Space$(256) 
    lRet = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, 0&, lngErrNum, 0&, sRtrnCode, Len(sRtrnCode), 0&) 
    If lRet > 0 Then 
     Translate_DLL_Error = Replace$(Left(sRtrnCode, lRet), vbCrLf, "") 
    Else 
     Translate_DLL_Error = "Error not found." 
    End If 

    Exit Function 

errTranslateDLLError(: 
    TranslateDLLError(= "Unable to translate system error: " & CStr(lngErrNum) 

End Function 
-1

Pruebe esto. Tiene que asociar el archivo PDF con cualquier programa (como Acrobat x) para leer archivos PDF, luego puede abrir archivos PDF con ShellExecute.

+0

El OP dijo que se abrió desde Explorer. Ya está asociado. – Deanna

1

Tuve el mismo problema y no fue posible cambiar el código VB6. Así que tuve que encontrar otra solución ...

En mi caso era un archivo con la extensión ".xyz", pero en realidad era un archivo para Microsoft Word, como un archivo .doc.

Al hacer doble clic por primera vez, Windows solicita un programa para abrir el archivo. Después de eso, el doble clic funcionó bien. Pero el ShellExecute no lo hizo. El problema es que ShellExecute realiza un "clic derecho" -> "abrir" en el archivo, y "abrir" no existe en el menú contextual en mi archivo .xyz. Solo había una "edición" ... Así que el ShellExecute funcionaba con "editar", pero no con "abrir" como el segundo parámetro.

Y como no pude cambiar el código VB6, abrí el registro con regedit. En la ruta "HKEY_CLASSES_ROOT \ .doc", el valor estándar era "Word.Document.8", en "HKEY_CLASSES_ROOT \ .xyz" solo había "xyz_auto_file". Así que cambié solo este valor a "Word.Document.8", y todo funcionó perfectamente. Ahora tengo el mismo menú contextual que con un archivo .doc, cuando hago clic derecho en mi archivo .xyz.

Y también el ShellExecute funciona perfectamente ...

+1

Esta es la misma respuesta [dada por Anders] (http://stackoverflow.com/a/1194308/588306) – Deanna

1

tuve el mismo problema con un programa existente que utiliza el verbo en lugar de openNULL cuando se llama a la función ShellExecute. Pude solucionar el problema agregando el verbo open como described here usando el editor de registro en el controlador .pdf (el mío estaba en HKEY_CLASSES_ROOT\pdf_auto_file). Creo que esto es un problema dentro del instalador de Adobe Reader que a veces no agrega el verbo open durante la instalación.

Aquí es la exportación de los valores del registro que ha añadido:

[HKEY_CLASSES_ROOT\pdf_auto_file\shell\Open\command] 
@="\"C:\\Program Files\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe\" \"%1\"" 
1

me encontré con el mismo problema que la OP dentro de una aplicación compilada Visual Foxpro 9 después de la actualización de W7x64 a W10 lanzamiento público.

Tengo instalado Adobe Acrobat y Adobe Reader. Cambiando la asociación .pdf predeterminada de Reader a Acrobat y ... ¡Todo funciona!Cambiando nuevamente a Reader con falla original (código de error 31 - "No hay ninguna aplicación asociada con la extensión de nombre de archivo dada"). Me gana, pero afortunadamente no tengo que preocuparme. Soy demasiado viejo para importarme y requeriré que todos los sitios permanezcan con W7.

asociación trabaja desde cualquier explorador de archivos

1

Llamar a una versión Unicode (ShellExecuteW) de un orden que sólo es compatible con ANSII, experimentado con una versión reciente de Inno Setup. ShellExecuteW funcionó para algunos argumentos de cadena ANSII, pero en este caso no es el requerido, devolviendo 2 (vea below).
Como cuestión de interés, ya sea en ANSII o Unicode, la función interna de Inno ShellExec también falló con el código 5 por el motivo de que el proceso de compilación aún tenía un identificador abierto para el archivo.

Cuestiones relacionadas