Pergunta

No meu último ambiente de desenvolvimento, eu era capaz de facilmente interagir com COM, chamando métodos em COM objetos. Aqui está o código original, traduzido para o código C # estilo (para mascarar a língua original):

public static void SpawnIEWithSource(String szSourceHTML)
{
    OleVariant ie; //IWebBrowser2
    OleVariant ie = new InternetExplorer();
    ie.Navigate2("about:blank");

    OleVariant webDocument = ie.Document;
    webDocument.Write(szSourceHTML);
    webDocument.close;

    ie.Visible = True;
}

Agora começa a tedioso e doloroso, processo de tentar interoperabilidade com COM do código gerenciado.

PInvoke.net já contém o IWebBrower2 tradução, o porition relavent de que é:

[ComImport, 
   DefaultMember("Name"), 
   Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"), 
   InterfaceType(ComInterfaceType.InterfaceIsIDispatch), 
   SuppressUnmanagedCodeSecurity]
public interface IWebBrowser2
{
    [DispId(500)]
    void Navigate2([In] ref object URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers);

    object Document { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xcb)] get; }
}

Eu criei a classe COM:

[ComImport]
[Guid("0002DF01-0000-0000-C000-000000000046")]
public class InternetExplorer
{
}

Portanto, agora é tempo para a minha transação real C #:

public static void SpawnIEWithSource(String szHtml)
{
    PInvoke.ShellDocView.IWebBrowser2 ie;
    ie = (PInvoke.ShellDocView.IWebBrowser2)new PInvoke.ShellDocView.InternetExplorer();

    //Navigate to about:blank to initialize the browser
    object o = System.Reflection.Missing.Value;
    String url = @"about:blank";
    ie.Navigate2(ref url, ref o, ref o, ref o, ref o);

    //stuff contents into the document
    object webDocument = ie.Document;
    //webDocument.Write(szHtml);
    //webDocument.Close();

    ie.Visible = true;
}

Os leitores cuidadosos notar que IWebBrowser2.Document é um IDispatch ligação tardia. Estamos usando Visual Studio 2005, com .NET 2.0 em nosso, e nosso cliente do, máquinas.

Então, qual é o método .NET 2.0 para chamar métodos em um objeto que, em algum nível, só suporta tardia IDispatch?

Uma rápida busca Stack Overflow para usar IDispatch de C # vira para cima este post dizendo o que eu quero não é possível em .NET.

Assim, é possível usar COM do C # .NET 2.0?


A questão é que não há um padrão de design aceita que eu quero usar em C # /. NET. Trata-se de lançar o Internet Explorer fora do processo, e dando-lhe conteúdo HTML, o tempo todo não usar arquivos temporários.

A rejeitado idéia do projeto está hospedando o Internet Explorer em um WinForm.

Uma alternativa aceitável está lançando o sistema registrado navegador web, dando-lhe HTML para exibição, sem usar um arquivo temporário.

O obstáculo continua a usar COM objetos no mundo .NET. O problema específico envolve a realização de chamadas de ligação tardia para IDispatch sem precisar C # 4.0. (Isto é, durante a utilização .NET 2.0)

Foi útil?

Solução 2

Tarde obrigado IDispatch chamada é relativly fácil no .NET, embora mijo-pobre: ??

public static void SpawnIEWithSource(String szHtml)
{
    // Get the class type and instantiate Internet Explorer.
    Type ieType = Type.GetTypeFromProgID("InternetExplorer.Application");
    object ie = Activator.CreateInstance(ieType);

    //Navigate to the blank page in order to make sure the Document exists
    //ie.Navigate2("about:blank");
    Object[] parameters = new Object[1];
    parameters[0] = @"about:blank";
    ie.GetType().InvokeMember("Navigate2", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, ie, parameters);

    //Get the Document object now that it exists
    //Object document = ie.Document;
    object document = ie.GetType().InvokeMember("Document", BindingFlags.GetProperty | BindingFlags.IgnoreCase, null, ie, null);

    //document.Write(szSourceHTML);
    parameters = new Object[1];
    parameters[0] = szHtml;
    document.GetType().InvokeMember("Write", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, document, parameters);

    //document.Close()
    document.GetType().InvokeMember("Close", BindingFlags.InvokeMethod | BindingFlags.IgnoreCase, null, document, null);

    //ie.Visible = true;
    parameters = new Object[1];
    parameters[0] = true;
    ie.GetType().InvokeMember("Visible", BindingFlags.SetProperty | BindingFlags.IgnoreCase, null, ie, parameters);
}

A questão SO referenciada que originalmente disse que "não é possível até C # 4.0" foi alterado para mostrar como é possível no .NET 2.0.

Does C # .NET suporte IDispatch ligação tardia?

Outras dicas

Update: Com base em atualizações pergunta, eu removi as partes da minha resposta que já não são relevantes para a questão. No entanto, no caso de outros leitores estão procurando uma maneira rápida e suja para gerar HTML em um aplicativo winforms e não necessitam de um in-process IE, vou deixar o seguinte:

Cenário Possível 1: O objetivo final é simplesmente exibir HTML para o usuário final e estão usando o Windows Forms

System.Windows.Forms.WebBrowser é o wrapper .NET meticulosamente fácil para a interface que está a tentar implementar manualmente. Para obtê-lo, arraste e solte uma instância do objeto de sua barra de ferramentas (listado como "Web Browser" na seção "All Windows Forms") para seu formulário. Então, em algum manipulador de eventos apropriado:

webBrowser1.Navigate("about:blank");
webBrowser1.Document.Write("<html><body>Hello World</body></html>");

No meu aplicativo de teste, este exibido corretamente a mensagem assustadora tudo o que aprendemos a temer e relutante.

As respostas no post que você conectar-se a são realmente incorreta. Em geral, é muito fácil de lidar com objetos com base IDispatch em .Net. Basicamente você passar por três etapas:

A maioria dos objetos de automação (provavelmente bem mais de 90%) que são expostos como interfaces de IDispatch tem outras interfaces que podem ser usados ??por clientes de tipo COM non-scripting (a interface IDispatch é na verdade uma interface COM completa derivada de IDispatch ou o objeto suporta um ou mais outras interfaces IUnknown derivados). Neste caso, você poderia simplesmente importar a definição de interface COM apropriado e, em seguida, converter o objeto para a interface apropriada. O elenco chama QueryInterface debaixo das cobertas e retorna uma referência embrulhado para a interface que você deseja.

Esta é a técnica que você usaria no cenário que você apresentado acima. O objeto Document que é retornado do objeto de automação IE suporta as interfaces IHTMLDocument, IHTMLDocument2, IHTMLDocument3, IHTMLDocument4 e IHTMLDocument5 (dependendo da versão do IE você está usando). Você deve converter para a interface apropriada e, em seguida, chamar o método apropriado. Por exemplo:

IHTMLDocument2 htmlDoc = (IHTMLDocument2)webDocument;
htmlDoc.Write(htmlString);
htmlDoc.Close();

No caso raro em que o objeto de automação não suporta uma interface alternativa. Então você deve usar VB.Net para embrulhar essa interface. Com Opção rigoroso conjunto para fora (somente para a classe wrapper) você pode usar o VB suporte embutido para chamadas dependente atrasado para simplesmente chamar os métodos IDispatch apropriados sob as cobertas. Em casos raros com os tipos de argumento incomum que você pode precisar mexer um pouco com a chamada, mas, em geral, em VB você pode apenas fazê-lo! Mesmo com as adições dinâmicos para C # v4 VB ainda terá provavelmente significativamente melhor suporte para chamadas COM ligação tardia.

Se por algum motivo você não pode usar o VB para embrulhar o interface de automação, em seguida, você ainda pode fazer todas as chamadas necessárias de C # usando reflexão. Eu não vou entrar em detalhes uma vez que esta opção deve basicamente nunca mais ser usado, mas aqui é um pequeno exemplo envolvendo Escritório automação .

Veja este artigo: http://www.codeproject.com/KB/cs/IELateBindingAutowod.aspx

Internet Explorer Tarde Automation Encadernação Por yincekara

Internet Explorer código de exemplo de automação usando a ligação tardia, sem Microsoft.mshtml e dependência shdocvw.

para htmlDoc.write (htmlString); modificar

   [Guid("332C4425-26CB-11D0-B483-00C04FD90119")]
    [ComImport]
    [TypeLibType((short)4160)]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
    internal interface IHTMLDocument2
    {
        [DispId(1054)]
        void write([MarshalAs(UnmanagedType.BStr)] string psArray);
        //void write([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] object[] psarray);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top