Pergunta

A descrição

Estou escrevendo alguns UDFs do Excel em servidores COM.Gostaria de obter a ajuda padrão (Inserir função caixa de diálogo) que você obtém quando pressiona efeitos.Sim, posso ver meu servidor COM listado no menu suspenso Categoria, mas

  • Também vejo Equals, GetHashCode, GetType e ToString (que são bastante indesejáveis ​​para expor ao usuário do Excel),
  • selecionar meu servidor COM abre a caixa de diálogo *Argumentos de função*[1] sem informações de argumento e sem descrição da função.

Aqui está a claudicação que recebo:

Caixa de diálogo Inserir função http://www.iwebthereforeiam.com/files/Insert%20function%20dialog.gif

Caixa de diálogo Argumentos de funções do Excel http://www.iwebthereforeiam.com/files/Function%20Arguments%20dialog.gif

A questão

Existem atributos .NET que eu poderia colocar nos métodos para passar isso para o Excel?

  • Posso fornecer uma descrição da função?
  • Posso fornecer uma descrição dos parâmetros?
  • Posso fornecer um nome de categoria para minhas funções, para obter algo melhor do que apenas o ProgID?

(Vejo que parece fácil de fazer no ExcelDNA, mas não estou seguindo esse caminho.Emular o código do govert [atributos personalizados, algum tipo de carregador, etc.] parece ser muito difícil.)


Antecedentes adicionais

Se você nunca trabalhou com servidores Excel + COM antes, aqui estão alguns recursos úteis para se atualizar:

Perguntas anteriores do StackOverflow:
Como instalar o COM Server for Excel escrito em VB.NET e registrá-lo na lista de servidores de automação?
Como adicionar um projeto .NET exposto ao COM à caixa de diálogo de referências do VB6 (ou VBA)?

Outros recursos:
Escrevendo funções definidas pelo usuário para Excel em .NET
Construir e implantar um assembly .NET COM
Escrevendo funções personalizadas de planilha do Excel em C#


Editar 20/10/2009 14:10

Eu tentei ligar Application.MacroOptions em um Sub New().

  1. Sem subnovo()
    Semi-aceitável:A função está listada na categoria ProgID.
  2. Subcompartilhado Novo()
    Não aceitável:erro em tempo de construção.
    Cannot register assembly "...\Foo.dll".
    Exception has been thrown by the target of an invocation.
  3. Subnovo()
    Não aceitável:categoria não está listada na caixa de diálogo Inserir função.

Suspeito que isso seja um problema tanto para MacroOptions quanto para a rota mais envolvente recomendada por Charles.


Editar 20/10/2009 14:55

Do lado positivo, a recomendação de Mike de criar uma interface para implementação eliminou os métodos extras irritantes que foram expostos.


Editar 20/10/2009 15:00

Este artigo da Microsoft desde o início de 2007 (via Link do Mike) parece uma resposta bastante completa sobre o assunto:

Suplementos de automação e a função Mago

Cada suplemento de automação tem seu próprio no Assistente de Função do Excel.O nome da categoria é o ProgID para o Suplemento;não é possível especificar um nome de categoria diferente para automação Funções de suplemento.Além disso, há não é possível especificar a função descrições, descrições de argumentos, ou ajuda para o Suplemento de Automação funções no Assistente de função.


1 Hum, um bug do StackOverFlow.Parece que você não pode colocar uma string em itálico dentro de uma ul-list HTML explícita?

Foi útil?

Solução

Parte disso é fácil de corrigir, outras partes são bastante difíceis.Tudo isso é possível, porém, se você estiver disposto a investir tempo.

Você escreveu:

Eu também vejo Equals, GetHashCode, GetType e ToString (que são bastante indesejável para expor ao Usuário do Excel)

Sim, concordo, isso é definitivamente indesejável, mas pode ser evitado.Isso está ocorrendo porque sua classe está herdando de 'System.Object', como todas as classes .NET fazem, e sua interface padrão exposta ao COM inclui esses membros.Isso ocorre, por exemplo, se você utilizar o 'ClassInterfaceAttribute', utilizando a configuração 'ClassInterfaceType.AutoDual'.

Por exemplo.em C#:

[ClassInterface(ClassInterfaceType.AutoDual)]

Em VB.NET:

<ClassInterface(ClassInterfaceType.AutoDual)>

O uso de 'ClassInterfaceType.AutoDual' deve ser evitado, entretanto, para evitar que os membros herdados de 'System.Object' sejam expostos (bem como para evitar possíveis problemas de versão no futuro).Em vez disso, defina sua própria interface, implemente a interface em sua classe e marque sua classe com o atributo 'ClassInterface' com um valor 'ClassInterfaceType.None'.

Por exemplo, usando C#:

[ComVisible(true)]
[Guid("5B88B8D0-8AF1-4741-A645-3D362A31BD37")]
public interface IClassName
{
    double AddTwo(double x, double y);
}

[ComVisible(true)]
[Guid("010B0245-55BB-4485-ABAF-46DF4356DB7B")]
[ProgId("ProjectName.ClassName")]
[ComDefaultInterface(typeof(IClassName))]
[ClassInterface(ClassInterfaceType.None)]
public class ClassName : IClassName
{
    public double AddTwo(double x, double y)
    {
        return x + y;
    }
}

Usando VB.NET:

<ComVisible(True)> _
<Guid("5B88B8D0-8AF1-4741-A645-3D362A31BD37")> _
Public Interface IClassName
    Function AddTwo(ByVal x As Double, ByVal y As Double) As Double
End Interface

<ComVisible(True)> _
<Guid("010B0245-55BB-4485-ABAF-46DF4356DB7B")> _
<ProgId("ProjectName.ClassName")> _
<ComDefaultInterface(GetType(IClassName))> _
<ClassInterface(ClassInterfaceType.None)> _
Public Class ClassName
    Implements IClassName

    Public Function AddTwo(ByVal x As Double, ByVal y As Double) As Double _
        Implements IClassName.AddTwo
        Return x + y
    End Function
End Class

Ao fazer uso de 'ClassInterfaceAtribute' com um valor de 'ClassInterfaceType.None', os membros 'System.Object' herdados são excluídos, porque a interface da classe não se torna visível para COM.Em vez disso, apenas a interface implementada ('IClassName' neste exemplo) é exportada para COM.

O texto acima também faz uso do 'ComDefaultInterfaceAttribute'.Isso não é muito importante e não faz nada se você implementar apenas uma interface - como neste exemplo - mas é uma boa ideia caso você adicione uma interface posteriormente, como IDTExtensibility2.

Para mais detalhes sobre isso, consulte:

(1) Suplementos de automação gerenciada por Andrew Whitechapel.

(2) Escrevendo funções personalizadas de planilha do Excel em C# por Gabhan Berry.

Ok, agora vamos à parte difícil.Você escreveu:

Selecionar meu servidor COM traz o Argumentos de função[1] diálogo sem informações de argumento e sem descrição da função.

Posso fornecer uma descrição do função?

Posso fornecer uma descrição do Parâmetros?

Posso fornecer um nome de categoria para o meu funções, para que eu consiga algo melhor do que apenas o ProgID?

A abordagem mais fácil aqui é fazer uso do Aplicativo.MacroOptions método.Este método permite fornecer uma descrição da função e especificar em qual categoria você deseja que ela seja exibida.Essa abordagem não permite especificar nenhuma informação para os parâmetros das funções, infelizmente, mas as técnicas que permitem fazer isso são muito complicadas, das quais falarei mais tarde. [Correção:O método 'Application.MacroOptions' funciona apenas para UDFs criados via VBA e não pode ser usado para suplementos de automação.Continue lendo para abordagens mais complexas para lidar com o registro de UDFs contidos em suplementos de automação - Mike Rosenblum 2009.10.20]

Observe que o arquivos de ajuda para Excel 2003 e arquivos de ajuda para Excel 2007 declare que uma string pode ser fornecida ao argumento de categoria para fornecer um nome de categoria personalizado de sua escolha.Cuidado, porém, que o arquivos de ajuda para Excel 2002 não.Não sei se isso é uma omissão nos arquivos de ajuda do Excel 2002 ou se é um novo recurso do Excel 2003.Suponho que seja o último, mas você teria que testar para ter certeza.

A única maneira de obter informações de parâmetro no Assistente de Função é usar uma técnica bastante complexa envolvendo o método 'Excel.Application.ExecuteExcel4Macro'.Porém, esteja avisado:muitos MVPs do Excel têm lutado com essa abordagem e não conseguem produzir um resultado confiável.Mais recentemente, porém, parece que Jan Karel Pieterse (JKP) resolveu o problema e publicou os detalhes aqui: Registrando uma função definida pelo usuário com Excel.

Folheando esse artigo você verá que não é para os fracos de coração.Parte do problema é que ele o escreveu para VBA/VB 6.0 e, portanto, todo esse código teria que ser traduzido para VB.NET ou C#.O comando principal, entretanto, é o método 'Excel.Application.ExecuteExcel4Macro', que é exposto ao .NET, então tudo deve funcionar bem.

Por uma questão prática, porém, prefiro usar a abordagem 'Excel.Application.MacroOptions' porque é simples e confiável.Ele não fornece informações de parâmetros, mas ainda não tive uma forte necessidade de me motivar a adotar a abordagem 'ExecuteExcel4Macro'.

Então, boa sorte com isso, mas meu conselho seria utilizar as 'MacroOptions', a menos que você esteja sendo pago por hora.;-)

-- Mike

Acompanhamento das respostas de Hugh

Tentei ligar Application.MacroOptions em um Sub Novo().

Não Sub New() Semi-aceitável:Função está listado na categoria ProgID.

Sub Compartilhado Novo() Não aceitável:erro em tempo de construção.Não é possível se cadastrar montagem "...\Foo.dll".Exceção tem foi lançado pelo alvo de um invocação.

Sub Novo() Não aceitável:categoria é não listado na caixa de diálogo Inserir função.Eu suspeito que isso é um problema tanto para MacroOptions e para os mais envolvidos rota recomendada por Charles.

Você não pode usar classes ou construtores compartilhados (também conhecidos como "estáticos") ao expor suas classes ao COM porque o COM não tem conhecimento desse conceito e, portanto, não pode compilar - como você descobriu!Você pode aplicar um 'COMVisibleAttribute' com um valor 'False' ao construtor compartilhado, para pelo menos permitir sua compilação.Mas isso não ajudaria você neste caso de qualquer maneira ...

Tentar registrar seu suplemento de automação por meio do próprio suplemento de automação pode ser complicado.Sei que isso é desejável para mantê-lo como um componente único e independente, mas pode não ser possível.Ou pelo menos isso não será fácil.

O problema é que os suplementos de automação são carregados sob demanda.Ou seja, eles não estarão realmente lá até que o Excel tente acessar a primeira função de planilha do seu suplemento de automação.Existem duas questões relacionadas a isso:

(1) Se você colocar seu código de registro no construtor de sua classe, então, por definição, as informações do assistente de função não poderão existir até que a função seja chamada pela primeira vez.

(2) Seu construtor pode estar em execução quando o Excel não estiver pronto para aceitar comandos de automação.Por exemplo, um suplemento de automação normalmente é carregado por demanda quando o usuário começa a digitar o nome de uma das UDFs (funções definidas pelo usuário) definidas no suplemento de automação.O resultado é que a célula estará no modo de edição quando o suplemento de automação for carregado pela primeira vez.Se você tiver código de automação em seu construtor durante o modo de edição, muitos comandos falharão.Não sei se os métodos 'Excel.Application.MacroOptions' ou 'Excel.Application.Excel4Macro' apresentam algum problema com isso, mas muitos comandos irão engasgar ao tentar executar enquanto a célula estiver em modo de edição.E se o suplemento de automação estiver sendo carregado pela primeira vez porque está sendo chamado enquanto o Assistente de Função está aberto, não tenho ideia se esses métodos podem funcionar corretamente.

Não há uma solução fácil para isso se você deseja que seu complemento de automação seja completamente independente, sem outro suporte.No entanto, você pode criar um suplemento COM gerenciado que registrará seu suplemento de automação por meio de 'Excel.Application.MacroOptions' ou da abordagem 'Excel.Application.Excel4Macro' quando o Excel for inicializado.A classe de suplemento COM gerenciado pode estar no mesmo assembly do seu suplemento de automação, portanto, você ainda precisará apenas de um assembly.

A propósito, você pode até usar uma pasta de trabalho VBA ou um complemento .XLA para fazer o mesmo - use o evento Workbook.Open no VBA para chamar o código de registro.Você só precisa algo para chamar seu código de registro quando o Excel for inicializado.A vantagem de usar VBA neste caso é que você pode utilizar o código do livro de Jan Karel Pieterse Registrando uma função definida pelo usuário com Excel artigo como está, sem precisar traduzi-lo para .NET.

No lado positivo, Mike Recomendação para criar uma interface para implementar matou o irritante métodos extras que foram expostos.

haha, que bom que algo funcionou!

Este artigo da Microsoft do início de 2007 (via link do Mike) parece um pouco Resposta completa sobre o tema:

Suplementos de automação e a função Mago

Cada suplemento de automação tem seu próprio no Assistente de Função do Excel.O nome da categoria é o ProgID para o Suplemento;não é possível especificar um nome de categoria diferente para automação Funções de suplemento.Além disso, há não é possível especificar a função descrições, descrições de argumentos, ou ajuda para o Suplemento de Automação funções no Assistente de função.

Esta é uma limitação apenas para a abordagem 'Excel.Application.MacroOptions'.(Minhas desculpas, eu tinha esquecido essa limitação do método 'Excel.Application.MacroOptions' em relação aos suplementos de automação quando escrevi minha resposta original acima.) O mais complexo 'Excel.Application.A abordagem ExecuteExcel4Macro, no entanto, funciona absolutamente para suplementos de automação.Ele também deve funcionar para suplementos de automação .NET ("gerenciados"), porque o Excel não tem ideia se está carregando um suplemento de automação COM criado via VB 6.0/C++ versus um suplemento de automação COM gerenciado criado usando VB.NET/C#.A mecânica é exatamente a mesma do lado COM da cerca porque o Excel não tem ideia do que é .NET, ou mesmo que o .NET exista.

Dito isto, a abordagem 'Excel.Application.Excel4Macro' definitivamente daria muito trabalho ...

Outras dicas

Você pode usar um dos sistemas .Net Excel, como ExcelDNA ou ADDIN Express, ou tentar adaptar uma das soluções VBA/VB6:veja FunCustomize de Laurent Longrehttp://xcell05.free.fr/english/index.htmlou o artigo de Jan Karel Pieterse em http://www.jkp-ads.com/Articles/RegisterUDF00.aspque usa um hack de sobrecarga de função.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top