Compartilhar via


Visão geral sobre interoperabilidade entre WPF e Win32

Este tópico fornece uma visão geral sobre como interoperar WPF e Win32 código. Windows Presentation Foundation (WPF) provides a rich environment for creating applications. No entanto, quando se tem um investimento significativo em código Win32, talvez seja mais eficiente reutilizar parte desse código.

Este tópico contém as seguintes seções.

  • Introdução a interoperaão entre WPF e Win32
  • Projetos de interoperação WPF
  • Como o WPF usa Hwnds
  • Hospedando conteúdo WPF em uma janela Microsoft Win32
  • Hospedando uma janela Microsoft Win32 no WPF
  • Uso da tecla TAB, mnemônicos e aceleradores
  • Tópicos relacionados

Introdução a interoperaão entre WPF e Win32

Há duas técnicas básicas de interoperação entre código WPF e Win32.

  • Hospedar conteúdo WPF em uma janela Win32. Com essa técnica, você pode usar os recursos avançados de elementos gráficos do WPF dentro da estrutura de uma janela ou aplicativo padrão Win32.

  • Hospedar conteúdo Win32 em uma janela WPF. Com essa técnica, você pode usar um controle Win32 personalizado já existente em um contexto de outro conteúdo WPF; e passar dados através dos limites entre eles.

Cada um dessas técnicas é apresentada conceitualmente neste tópico. Para uma exemplificação mais orientada a código sobre hospedagem de conteúdo WPF no Win32, consulte Demonstra Passo a passo: Hospedagem de um controle de Win32 simples em um aplicativo do Windows Presentation Foundation. Para uma exemplificação mais orientada a código sobre hospedagem de conteúdo Win32 no WPF, consulte Demonstra Passo a passo: Hospedagem de conteúdo do Windows Presentation Foundation em um aplicativo Win32.

Projetos de interoperação WPF

As APIs do WPF são em código gerenciado, mas a maioria dos programas Win32 existentes são escritos em C++ não gerenciado. Você não pode chamar APIs WPF a partir de um programa verdadeiramente não gerenciado. No entanto, usando a opção /clr do compilador Microsoft Visual C++, você pode criar um programa gerenciado misto onde você pode misturar perfeitamente chamadas de API tanto gerenciadas quanto não gerenciadas.

Uma complicação no nível de projeto é que você não pode compilar arquivos Extensible Application Markup Language (XAML) em um projeto C++. Há várias técnicas de divisão de projeto para compensar isso.

  • Criar uma DLL C# que contém todas as suas páginas XAML como um conjunto de módulos (assembly) compilado e então fazer com que o executável C++ inclua a DLL como uma referência.

  • Criar um executável C# para o conteúdo WPF, e fazer com que ele referencie uma DLL C++ que contém o conteúdo Win32.

  • Usar Load para carregar qualquer arquivo XAML em tempo de execução, em vez de compilar o XAML.

  • Não usar XAML algum e escvrever todo seu conteúdo WPF em código, construíndo a árvore de elementos de Application.

Use a abordagem que funcionar melhor para você.

ObservaçãoObservação:

Se você tiver não usado C + + / CLIantes, você poderá notar algumas palavras-chave "new", sistema autônomo gcnew e nullptr sistema autônomo exemplos de código de interoperação. Essas palavras-chave substitui o antigo (sintaxe sublinhado duplo__gc) e fornecem uma sintaxe mais natural para código gerenciado em C++. Para obter mais informações sobre o C + + / CLI recursos gerenciado, consulte Novo Features Idioma in Visual C++ e Olá, C + c++ / CLI.

Como o WPF usa Hwnds

Para aproveitar ao máximo a "interoperabilidade HWND" do WPF, você precisará compreender como o WPF usa HWNDs. Para qualquer HWND, você não pode misturar renderização WPF com renderização DirectX ou com renderização GDI / GDI+. Isso tem um número de implicações. Basicamente, para misturar esses modelos de renderização, você deve criar uma solução de interoperabilidade e usar segmentos de interoperação designados para cada modelo de renderização que você escolher usar. Além disso, o comportamento de renderização cria uma restrição de "airspace" para o que sua solução de interoperação pode realizar. O conceito de "airspace" é explicado em detalhes no tópico Interoperação do WPF: Visão geral de regiões de janela e "Airspace" maior.

Todos os elementos WPF na tela são, em última instância, fundamentados em um HWND. Quando você cria uma Window WPF, o WPF cria um HWND de alto nível e usa um HwndSource para colocar a Window e seu conteúdo WPF dentro do HWND. O restante do seu conteúdo WPF no aplicativo compartilha aquele único HWND. Uma exceção são os menus, caixas de combinação e demais pop-ups. Esses elementos criam sua própria janela de alto nível, o que é o motivo pelo qual um menu WPF potencialmente pode passar da borda da janela HWND que a contém. Quando você usa HwndHost para colocar um HWND dentro do WPF, o WPF informa o Win32 como posicionar o novo filho HWND relativo ao HWND da Window WPF.

Um conceito relacionado a HWND é transparência dentro e entre cada HWND. Isso também é discutido no tópico Interoperação do WPF: Visão geral de regiões de janela e "Airspace".

Hospedando conteúdo WPF em uma janela Microsoft Win32

A chave para hospedar conteúdo WPF em uma janela Win32 é a classe HwndSource. Essa classe envolve o conteúdo WPF em uma janela Win32 para que o conteúdo WPF possa ser incorporado em sua interface do usuário (UI) como um janela filho. A abordagem a seguir combina a Win32 e WPF em um aplicativo único.

  1. Implemente o seu conteúdo WPF (o elemento conteúdo raiz) como uma classe gerenciada. Normalmente, a classe herda de uma das classes que podem conter vários elementos filho e/ou ser usadas como um elemento raiz, tais como DockPanel ou Page. Nas etapas subsequentes, essa classe é chamada de classe de conteúdo WPF, e as instâncias da classe são chamadas de objetos de conteúdo WPF.

  2. Implemente um aplicativo Win32 como C + + / CLI. Se você estiver começando com um aplicativo não gerenciado C++ já existente, você geralmente pode habilitá-lo a chamar código gerenciado alterando suas configurações de projeto para incluir a opção de compilador /clr (o escopo completo do que pode ser necessário para oferecer suporte à compilação /clr não é descrito neste tópico).

  3. conjunto o modelo de segmentação para STA (Single Threaded Apartment). WPF usa o modelo de threading.

  4. Trate a notificação WM_CREATE no procedimento de sua janela.

  5. Dentro do manipulador (ou de uma função que o manipulador chame), faça o seguinte:

    1. Crie um novo objeto HwndSource com o HWND da janela pai como seu parâmetro parent.

    2. Crie uma instância da sua classe de conteúdo WPF.

    3. Atribua uma referência ao objeto de conteúdo WPF à propriedade RootVisual do objeto HwndSource.

    4. A propriedade Handle do objeto HwndSource contém o manipulador de janela (HWND). Para obter um HWND que você possa usar na parte não gerenciada de seu aplicativo, converta Handle.ToPointer() para um HWND.

  6. Implemente uma classe gerenciada que contenha um campo estático que mantenha uma referência para seu objeto de conteúdo WPF. Esta classe permite que você obtenha uma referência para o objeto de conteúdo WPF a partir do seu código Win32, mas - mais importante - impede que seu HwndSource seja coletado inadvertidamente pelo coletor de lixo (GC).

  7. Receba notificações do objeto de conteúdo WPF anexando um manipulador a um ou mais eventos de objetos de conteúdo WPF.

  8. Comunique-se com o objeto de conteúdo WPF através da referência armazenada no campo estático para definir propriedades, chamar métodos, etc.

ObservaçãoObservação:

Você pode fazer algumas ou todas as WPF definição de classe de conteúdo para Step 1 no XAML usando a classe parcial do padrão da classe de conteúdo, se produzir um assembly separado e, em seguida, fazer referência a ela. Embora você normalmente incluem um Application objeto sistema autônomo parte da compilação do XAML em um assembly não termina usando e que Application sistema autônomo parte de interoperação, você só use um ou mais das classes de raiz para XAML arquivos chamados pelo aplicativo e suas classes parciais de referência. O restante do procedimento é esencialmente similar ao descrito acima.

Cada uma dessas etapas é ilustrada através de código do tópico Demonstra Passo a passo: Hospedagem de conteúdo do Windows Presentation Foundation em um aplicativo Win32 .

Hospedando uma janela Microsoft Win32 no WPF

A chave para hospedar uma janela Win32 dentro de outro conteúdo WPF é a classe HwndHost. Essa classe encapsula a janela em um WPF elemento que pode ser adicionado a um WPF árvore de elementos. HwndHost também oferece suporte APIs que permitem que você faça tarefas sistema autônomo processar mensagens para a janela hospedada. O procedimento básico é o seguinte:

  1. Crie uma árvore de elementos para um aplicativo WPF (pode ser por meio de código ou usando linguagem de marcação). Localize um ponto adequado e apropriado na árvore de elementos onde a implementação de HwndHost pode ser adicionada como um elemento filho. No restante dessas etapas, esse elemento é chamado de elemento de reserva.

  2. Derive de HwndHost para criar um objeto que contém o seu conteúdo Win32.

  3. Na classe host, sobrescreva o método BuildWindowCore de HwndHost. Retorne o HWND da janela hospedada. Talvez você deseje envolver o(s) controle(s) com uma janela filho da janela retornada; envolver os controles em uma janela host fornece uma maneira simples para seu conteúdo WPF receber notificações dos controles. Esta técnica ajuda a corrigir alguns problemas do Win32 em relação ao tratamento de mensagens no limiar do controle hospedado.

  4. Sobrescreva os métodos DestroyWindowCore e WndProc de HwndHost. A intenção aqui é processar a limpeza e remover referências para o conteúdo hospedado, especialmente se você tiver criado referências a objetos não gerenciados.

  5. No seu arquvio de código, crie uma instância da classe que hospeda controles e torne-a um filho do elemento de reserva. Normalmente você poderia usar um tratador de eventos como o Loaded, ou o construtor de classe parcial. Mas você pode também adicionar o conteúdo de interoperação através de um comportamento de tempo de execução.

  6. Processe as mensagens de janela selecionadas, como notificações de controle por exemplo. Há duas abordagens. Ambas fornecem acesso idêntico ao fluxo de mensagens, portanto sua escolha é principalmente uma questão de conveniência de programação.

    • Implementar o processamento de todas as mensagens (não apenas mensagens de desligamento) em sua sobrescrita do método WndProc de HwndHost.

    • Fazer com que o elemento WPF de hospedagem processe as mensagens ao tratar o evento MessageHook. Este evento é gerado para cada mensagem que é enviada para o procedimento da janela principal da janela hospedada.

    • Você não pode processar as mensagens de janelas que estão fora do processo usando WndProc.

  7. Comunique-se com a janela hospedada usando invocação de plataforma para chamar a função não gerenciada SendMessage.

As seguintes etapas criam um aplicativo que funciona com a entrada do mouse. Você pode adicionar suporte a TAB para sua janela hospedada implementando a interface IKeyboardInputSink.

Cada uma dessas etapas é ilustrada através de código no tópico Demonstra Passo a passo: Hospedagem de um controle de Win32 simples em um aplicativo do Windows Presentation Foundation.

Hwnds no WPF

Você pode pensar no HwndHost como um controle especial. (Tecnicamente, HwndHost é um FrameworkElement derivado de classe, não um Control classe derivada, mas pode ser considerado como um controle para fins de interoperação.) HwndHost abstrai base Win32 natureza do conteúdo hospedado, de forma que o restante do WPF considera o conteúdo hospedado seja outro objeto semelhante ao controle, que deve processar e entrada de processo. HwndHost generally behaves like any other WPF FrameworkElement, although there are some important differences around output (drawing and graphics) and input (mouse and keyboard) based on limitations of what the underlying HWNDs can support.

Diferenças perceptíveis no comportamento de saída

  • FrameworkElement que é a classe base de HwndHost, tem muito poucas propriedades que impliquem em alterações à interface do usuário. Estas incluem propriedades como FrameworkElement.FlowDirection, que altera o layout dos elementos que têm esse elemento como pai. No entanto, a maioria dessas propriedades não é mapeada para possíveis equivalentes Win32, mesmo se tais equivalentes podem existir. Um número excessivo dessas propriedades e seus significados são específicos demais da tecnologia de renderização para que mapeamentos sejam práticos. Portanto, definir propriedades como FlowDirection em HwndHost não tem efeito.

  • HwndHost não pode ser girado, escalado, inclinado ou afetados de algum outro modo por uma transformação.

  • HwndHost não tem suporte a propriedade Opacity (combinação do canal alfa). Se o conteúdo dentro do HwndHost executa operações de System.Drawing que incluem informações de canal alfa, isto não é propriametne uma violação, mas o HwndHost como um todo só oferece suporte a opacidade = 1,0 (100%).

  • O HwndHost será exibido sobre outros elementos WPF na mesma janela de alto nível. No entanto, um ToolTip ou um menu ContextMenu gerado estão em uma janela de alto nível separada e assim irão se comportar corretamente com o HwndHost.

  • O HwndHost não respeita a região de corte (clipping) de seu UIElement pai. Isso é potencialmente um problema se você tentar colocar uma classe HwndHost dentro de uma região de rolagem ou de um Canvas.

Diferenças perceptíveis no comportamento de entrada

  • Em geral, enquanto os dispositivos de entrada tem escopo dentro da região Win32 hospedada pelo HwndHost, eventos de entrada vão diretamente para o Win32.

  • Enquanto o mouse está sobre o HwndHost, seu aplicativo não recebe eventos WPF de mouse, e o valor da propriedade IsMouseOver do WPF será false.

  • Enquanto o HwndHost tem o foco de teclado, seu aplicativo não recebe eventos WPF de teclado e o valor da propriedade IsKeyboardFocusWithin do WPF será false.

  • Quando o foco está dentro do HwndHost e muda para outro controle dentro do HwndHost, seu aplicativo não receberá os eventos GotFocus e LostFocus do WPF.

  • Propriedades e eventos relacionados a caneta (stylus) são análogas e não relatam informações enquanto a caneta está sobre o HwndHost.

Uso da tecla TAB, mnemônicos e aceleradores

As interfaces IKeyboardInputSink e IKeyboardInputSite permitem que você crie uma experiência de teclado uniforme para aplicativos mistos WPF e Win32:

  • Uso de TAB entre componentes Win32 e WPF

  • Mnemônicos e aceleradores que funcionam quando o foco estiver em um componente Win32 e quando ele estiver em um componente WPF.

As classes HwndHost e HwndSource fornecem implementações de IKeyboardInputSink, mas elas podem não tratar todas as mensagens de entrada que você deseje em cenários mais avançados. Sobrescreva os métodos apropriados para obter o comportamento de teclado desejado.

As interfaces somente oferecem suporte para o que acontece na transição entre as regiões WPF e Win32. Dentro da região Win32, o comportamento do uso da tecla TAB é inteiramente controlado pela lógica implementada pelo Win32, se houver.

Consulte também

Conceitos

Demonstra Passo a passo: Hospedagem de um controle de Win32 simples em um aplicativo do Windows Presentation Foundation

Demonstra Passo a passo: Hospedagem de conteúdo do Windows Presentation Foundation em um aplicativo Win32

Referência

HwndHost

HwndSource

System.Windows.Interop