J'essaie d'obtenir la source HTML d'une page Web qui a été chargée dans un fichier de type WPF Contrôle du navigateur Web. La seule façon de le faire semble être de couler l'instance de WebBrowser.Document vers IPersistStreamInit (que je devrai définir moi-même, car il s'agit d'une interface COM) et d'appeler la méthode IPersistStreamInit.Save, en passant une une implémentation d'un IStream (encore une fois, une interface COM), qui persistera le document dans le flux. Enfin, en quelque sorte : Je reçois toujours les 4 premiers kilo-octets du flux, et non le document entier, et je ne sais pas pourquoi.
Voici le code de IPersistStreamInit :
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
namespace PayPal.SkyNet.BpiTool.Interop
{
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
SuppressUnmanagedCodeSecurity,
Guid("7FD52380-4E07-101B-AE2D-08002B2EC713")]
public interface IPersistStreamInit
{
void GetClassID(out Guid pClassID);
[PreserveSig]
int IsDirty();
void Load([In, MarshalAs(UnmanagedType.Interface)] IStream pstm);
void Save([In, MarshalAs(UnmanagedType.Interface)] IStream pstm, [In, MarshalAs(UnmanagedType.Bool)] bool fClearDirty);
void GetSizeMax([Out, MarshalAs(UnmanagedType.LPArray)] long pcbSize);
void InitNew();
}
}
Voici le code de l'implémentation de l'IStream :
using System;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
namespace PayPal.SkyNet.BpiTool.Interop
{
public class ComStream : IStream
{
private Stream _stream;
public ComStream(Stream stream)
{
this._stream = stream;
}
public void Commit(int grfCommitFlags)
{
}
public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
{
}
public void LockRegion(long libOffset, long cb, int dwLockType)
{
}
public void Read(byte[] pv, int cb, IntPtr pcbRead)
{
this._stream.Read(pv, (int)this._stream.Position, cb);
}
public void Revert()
{
}
public void SetSize(long libNewSize)
{
this._stream.SetLength(libNewSize);
}
public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
{
pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG();
}
public void UnlockRegion(long libOffset, long cb, int dwLockType)
{
}
public void Write(byte[] pv, int cb, IntPtr pcbWritten)
{
this._stream.Write(pv, 0, cb);
}
public void Clone(out IStream outputStream)
{
outputStream = null;
}
public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
{
this._stream.Seek(dlibMove, (SeekOrigin)dwOrigin);
}
}
}
Maintenant, j'ai un cours pour conclure tout ça. Comme je ne veux pas redistribuer l'assemblage mshtml-interop-assembly, j'ai choisi la liaison tardive - et comme la liaison tardive est plus facile en VB, je l'ai fait en VB. Voici le code :
Option Strict Off
Option Explicit Off
Imports System.IO
Public Class HtmlDocumentWrapper : Implements IDisposable
Private htmlDoc As Object
Public Sub New(ByVal htmlDoc As Object)
Me.htmlDoc = htmlDoc
End Sub
Public Property Document As Object
Get
Return Me.htmlDoc
End Get
Set(value As Object)
Me.htmlDoc = Nothing
Me.htmlDoc = value
End Set
End Property
Public ReadOnly Property DocumentStream As Stream
Get
Dim str As Stream = Nothing
Dim psi As IPersistStreamInit = CType(Me.htmlDoc, IPersistStreamInit)
If psi IsNot Nothing Then
str = New MemoryStream
Dim cStream As New ComStream(str)
psi.Save(cStream, False)
str.Position = 0
End If
Return str
End Get
End Property
End Class
Maintenant, je devrais être capable d'utiliser tout ça :
private void Browser_Navigated(object sender, NavigationEventArgs e)
{
HtmlDocumentWrapper doc = new HtmlDocumentWrapper();
doc.Document = Browser.Document;
using (StreamReader sr = new StreamReader(doc.DocumentStream))
{
using (StreamWriter sw = new StreamWriter("test.txt"))
{
//BOOM! Only 4kb of HTML source
sw.WriteLine(sr.ReadToEnd());
sw.Flush();
}
}
}
Quelqu'un sait-il pourquoi je n'obtiens pas l'intégralité de la source HTML ? Toute aide est la bienvenue.
Salutations
Arne