¿Cómo puedo devolver tanto una cadena de error y el código de error para VB6 de un control ActiveX ATL?
-
21-08-2019 - |
Pregunta
Estoy tratando de devolver un error detallado a VB6 utilizando CComCoClass :: error , pero parece que sólo puedo devolver un código de error / o / un mensaje -. pero no ambos
return Error(_T("Not connected"), __uuidof(IMyInterface), HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID));
resultados en un genérico "Método 'Solicitud' de 'IMyInterface' objeto" mensaje de error en Err.Description en el lado VB6 (pero ERROR_CONNECTION_INVALID en Err.Number), mientras
return Error(_T("Not connected"));
resultados en el mensaje de error apropiado, pero un código de error genérico en Err.Number. ¿Cómo puedo obtener lo mejor de ambos mundos?
Solución
No se puede, esto parece ser por diseño. Detalles más adelante, pero en definitiva tiene tres opciones:
- Vuelta ningún mensaje y un error COM amable VB, es decir, uno bien conocido por el tiempo de ejecución VB según esta artículo KB ; el tiempo de ejecución de VB se traducirá este 'error COM' a un error VB además de mensajes.
- devolverá un mensaje de error y DISP_E_EXCEPTION; el tiempo de ejecución de VB pasará a través de este 'Error del servidor' y su mensaje de error personalizado. Esto es lo que está sucediendo de forma implícita en su segundo ejemplo, véase más abajo para más detalles.
- Vuelta ningún mensaje y cualquier otro error COM, es decir, uno no conocido por el tiempo de ejecución VB; el tiempo de ejecución de VB recurrirá a la HRESULT prima más el mensaje genérico "
Method '~' of object '~' failed
".- Tenga en cuenta que este comportamiento en tiempo de ejecución también se aplica, si lo hace suministrar un mensaje de error aquí, es decir, su mensaje simplemente será ignorado! Esto es lo que está sucediendo en su primer ejemplo, véase más abajo para más detalles.
Para la tarea se reduce a dos opciones:
- Si desea proporcionar contextualmente correctos '' errores COM para clientes de automatización como VB (y probablemente debería) debe omitir los mensajes de error personalizados.
- Si desea proporcionar mensajes de error personalizados para los "errores del servidor (es decir, una condiciones de error personalizados en cuanto a la funcionalidad dentro de el servidor de automatización) su única opción es DISP_E_EXCEPTION.
Detalles
El tiempo de ejecución de VB parece ofrecer un manejo muy restringida solamente en lo que se refiere a los errores COM. Esto es probablemente por razones históricas y / o técnicos adaptados a la forma de VB se ha aplicado y no de particular interés aquí (palabras clave serían IDispatch única vs interfaz dual y ActiveX como un 'subconjunto' de COM).
Si bien no he podido salir a la superficie una especificación explícita para el comportamiento descrito anteriormente es posible comprenderla de excavación a través de otras fuentes:
Desde el artículo KB justadreamer ya se ha señalado :
[...] se hace una llamada a la GetErrorInfo método para recuperar la información de error disponible. los tiempo de ejecución determina entonces si bstrDescription tiene un valor distinto NULO. Si el tiempo de ejecución encuentra un valor distinto de NULL, [...], el HRESULT prima valor se utiliza en este escenario. Si el tiempo de ejecución encuentra un valor NULL, [...] Visual Basic utiliza entonces HRESULT para buscar el correspondiente Visual error básico.
Esto explica el comportamiento en relación con su puño ejemplo: usted hizo suministrar un mensaje de error, por lo tanto, el tiempo de ejecución simplemente recurre a su mensaje genérico "HRESULT
", además de su CComCoClass::Error
El comportamiento de su segundo ejemplo también es consistente vez que nos fijamos en la definición del constructor (primera lista) para <=> : tiene valores predeterminados para los parámetros no especificados, especialmente 'hRes = 0'. La sección 'Observaciones' afirma además que "Si hRes es cero, entonces los primeros cuatro versiones de DISP_E_EXCEPTION de retorno de error.". En consecuencia esto desencadena implícitamente el 'error de servidor' pasar a través de comportamiento.
Por último, para una muestra de C ++ concreta implementación de un VB como el comportamiento de los clientes de automatización ver por ejemplo los párrafos 'El manejo de errores' y la 'Ejercicio 5' siguiente en Automatización de Microsoft Office 97 y Microsoft Office 2000 .
Otros consejos
Derivar la clase que implementa la interfaz COM-expuesta desde ISupportErrorInfoImpl, llame SetErrorInfo para establecer la explicación detallada del error si se presenta alguna. No se olvide de incluir en el ISupportErrorInfo COM_MAP de su clase.
Estoy luchando con esto ahora también. Hasta ahora mi excavación indica que el código de error es realmente el valor HRESULT. VB6 trata de ser inteligente e interpretar el HRESULT pero parece tener una lista bastante limitado de HRESULT se entiende. Para el HRESULT VB6 no está familiarizado con, simplemente pone el HRESULT en la propiedad Err.Number y espera que el desarrollador es lo suficientemente inteligente como para saber qué hacer con él.
Lo más cerca que he llegado a devolver un número de error es mediante el uso MAKE_SCODE para generar un HRESULT con el campo de código de la HRESULT ajustado a lo que yo quiero, establece el indicador de gravedad y lo que espero es la instalación correcta.
Esto en conjunto con CreateErrorInfo y SetErrorInfo me traiga un código de error y una descripción del error en VB6. Y eso nos lleva de nuevo a VB6 tratando de ser inteligente con una lista limitada de errores.
http://support.microsoft.com/kb/827994 . Por lo que su objeto debe implementar el método ISupportsErrorInfo :: InterfaceSupportsErrorInfo () que devuelve S OK. y luego, antes de regresar se debe llamar SetErrorInfo con un puntero a un objeto COM que implementa IErrorInfo :: GetDescription (). Hay un ejemplo aquí: http://msdn.microsoft.com/en-us/library/ms221409. aspx .
Si SetErrorInfo antes de vuelta, VB consultará el método GetDescription del puntero de objeto que pasó a SetErrorInfo.
No soy demasiado profundo en el código atribuido que está utilizando - yo preferiría para probarlo mediante COM más crudo que seguramente es siempre una gran cantidad de código repetitivo - pero al menos funciona, entonces se podría usar envolturas sofisticados en lugar de a él.