Como posso devolver tanto uma string de erro e código de erro para VB6 de um controle ActiveX ATL?
-
21-08-2019 - |
Pergunta
Eu estou tentando retornar um erro detalhada para VB6 usando CComCoClass :: erro , mas parece que só pode retornar um código de erro / ou / a mensagem - mas não ambos
.return Error(_T("Not connected"), __uuidof(IMyInterface), HRESULT_FROM_WIN32(ERROR_CONNECTION_INVALID));
resulta em um genérico "Método 'Request' do objeto 'IMyInterface' falhou" mensagem de erro no Err.Description no lado do VB6 (mas ERROR_CONNECTION_INVALID em Err.Number), enquanto
return Error(_T("Not connected"));
resulta na mensagem de erro apropriada, mas um código de erro genérico em Err.Number. Como posso obter o melhor dos dois mundos?
Solução
Você não pode, este parece ser por design. Detalhes mais adiante, mas em suma, você tem três opções:
- Voltar nenhuma mensagem e um erro amigável COM VB, ou seja, um conhecido pelo tempo de execução VB de acordo com esta KB artigo ; o tempo de execução VB irá traduzir este 'erro COM' a um erro VB além de mensagem.
- retornar uma mensagem de erro e DISP_E_EXCEPTION; o tempo de execução VB vai passar por este 'Erro de servidor' e sua mensagem de erro personalizada. Isto é o que está acontecendo implicitamente em seu segundo exemplo, veja abaixo para mais detalhes.
- Voltar nenhuma mensagem e qualquer outro erro COM, isto é, um não conhecido pelo tempo de execução VB; o tempo de execução VB irá recorrer ao HRESULT cru mais a mensagem genérica "
Method '~' of object '~' failed
".- Por favor note que este comportamento de tempo de execução também se aplica, se você fornecer uma mensagem de erro aqui, ou seja, a sua mensagem será simplesmente ignorado! Isto é o que está acontecendo em seu primeiro exemplo, veja abaixo para mais detalhes.
Para a tarefa em mãos tudo se resume a duas escolhas:
- Se você quiser fornecer 'erros COM' contextualmente corretas para clientes de automação como VB (e provavelmente você deve), você deve omitir mensagens de erro personalizadas.
- Se você quiser fornecer mensagens de erro personalizada para 'erros servidor' (uma condição de erro personalizadas ou seja, sobre a funcionalidade dentro o seu servidor de automação) sua única opção é DISP_E_EXCEPTION.
Detalhes
O tempo de execução VB parece oferecer muito restrito manipulação no que diz respeito a erros COM. Isto é provavelmente por razões históricas e / ou técnicas específicas para o caminho VB foi implementado e não de particular interesse aqui (palavras-chave seria IDispatch única vs interface dupla e ActiveX como um 'subconjunto' de COM).
Enquanto eu fui incapaz de superfície uma especificação explícita para o comportamento descrito acima pode-se entender de cavar através de outras fontes:
A partir do artigo KB justadreamer apontou já :
[...] é feita uma chamada para o método GetErrorInfo para recuperar o informações de erro disponível. o runtime, em seguida, determina se bstrDescription tem um valor diferente de NULO. Se o tempo de execução encontra um valor diferente de NULL, [...], o HRESULT crua valor é usado neste cenário. Se o tempo de execução encontra um valor NULL, [...] Visual Basic, em seguida, usa HRESULT para procurar o correspondente Visual erro básico.
Isso explica o comportamento em relação a sua exemplo punho:. Que você fez fornecer uma mensagem de erro, portanto, o tempo de execução simplesmente recorre a sua mensagem genérica "Method '~' of object '~' failed
" plus seu HRESULT
O comportamento do seu segundo exemplo também é consistente uma vez que você olhar para a definição do construtor (primeiro da lista) para CComCoClass::Error
: tem padrões para os parâmetros não especificada, especialmente 'hRes = 0'. A secção 'Observações' afirma ainda que "Se hRes é zero, então os primeiros quatro versões de DISP_E_EXCEPTION retorno de erro.". Consequentemente, esta desencadeia implicitamente o passe 'Erro de servidor' através de um comportamento.
Finalmente, para um concreto C ++ amostra implementação de um VB como o comportamento do cliente de automação ver por 'Erro de manipulação' exemplo parágrafos e o seguinte 'Exercício 5' em Automatizando Microsoft Office 97 e Microsoft Office 2000 .
Outras dicas
derivar a classe que implementa a interface exposta-COM da ISupportErrorInfoImpl, chamar SetErrorInfo para definir a explicação detalhada do erro se houver ocorre. Não se esqueça de incluir ISupportErrorInfo no COM_MAP de sua classe.
Eu estou lutando com isso agora também. Até agora o meu escavação indica que o código de erro é realmente o valor HRESULT. VB6 tenta ser inteligente e interpretar o HRESULT mas parece ter uma lista bastante limitada de HRESULTs ele entende. Para o HRESULTs VB6 não está familiarizado com, ele apenas coloca o HRESULT para a propriedade Err.Number e espera que o desenvolvedor é inteligente o suficiente para descobrir o que fazer com ele.
O mais próximo que eu vim para retornar um número de erro é usando MAKE_SCODE para gerar um HRESULT com o campo de código do conjunto HRESULT para o que eu quero, o jogo da bandeira gravidade e que eu espero é a facilidade direita.
Isso em conjunto com CreateErrorInfo e SetErrorInfo me um código de erro e uma descrição de erro em VB6. E isso nos traz de volta ao VB6 tentando ser inteligente com uma lista limitada de erros.
Checkout este artigo http://support.microsoft.com/kb/827994 . Portanto, o seu objeto deve implementar o método ISupportsErrorInfo :: InterfaceSupportsErrorInfo () que retorna S_OK. e, em seguida, antes de retornar você deve chamar SetErrorInfo com um ponteiro para um objeto COM que implementa IErrorInfo :: GetDescription (). Há um exemplo aqui: http://msdn.microsoft.com/en-us/library/ms221409. aspx .
Se você SetErrorInfo antes do retorno, VB irá consultar o método GetDescription do ponteiro do objeto que você passou para SetErrorInfo.
Eu não sou muito profundo no código atribuído você estiver usando - Eu preferiria testá-lo usando COM mais cru que é certamente sempre um monte de código clichê - mas pelo menos ele funciona, então você poderia usar invólucros sofisticados em vez de -lo.