HTML Renderer

M

Michael C

Interesting. That method was taken largely from an example on the MS
website... Guess they need to fix their samples and use their methods in a
more correct fashion. Got any examples of code using IPersistMemory? Noah
Coad published a WebBrowser wrapper control that exposes properties to
assign the HTML directly. His code is at
http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=312. I
don't believe he defines IPersistMemory either.

Thanks,
Michael C., MCDBA


Nicholas Paldino said:
Personally, I wouldn't use that method, as I don't believe it was
intended for this.

Rather, what I would do is define the COM interface IPersistMemory in
your assembly. You can find the definition in Ocidl.idl. Once you have
that, you can cast the value returned from the document property (after you
navigate to about:blank to get an instance loaded) to this interface and
then call Load in order to load the document from memory.

The thing here is that it expects a pointer, in which case, you will
have to copy the content to unmanaged code, or you will have to use unsafe
code to fix the location of the data in memory and then make the call.

Hope this helps.



Michael C said:
I posted some code to do this already. The post is called "Re:
AxSHDocVw.AxWebBrowser Component Question", the date was 10/9.

Thanks,
Michael C., MCDBA

John Lee said:
Hi, Nick,

Could you please show me the code how you can feed html or xml to the web
browser in memory? I can only do it by creating a temp file and supply
the
url. ..

Thanks!
John
"Nicholas Paldino [.NET/C# MVP]" <[email protected]>
wrote
in
message Michael,

I don't understand why you wouldn't use the webbrowser? How are you
trying to feed the HTML to it? It's pretty simple, you can do it through
memory, or through a file, or through a number of other mechanisms.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Anyone know of a good HTML Rendering control? I need a control that will
render and display HTML in a Windows form. It doesn't need to pull down
HTML pages from the Web - I'll feed it all the HTML it needs to display.
I've already spent way too much time trying to get the Microsoft
WebBrowser
control to work, and I have too many other things to work on to
waste
any
more time on it. If you know of any third-party HTML Renderers out
there,
please let me know.

Thanks,
Michael C., MCDBA
 
N

Nicholas Paldino [.NET/C# MVP]

Michael,

You know, I could have sworn that IPersistMemory was on MSHTML.
Apparently, it is not.

I still wouldn't use the writeln function though (although for a quick
fix, I can't say don't use it).

The solution I use (a long time ago) was to fake a moniker and pass it
to the IPersistMoniker interface (the moniker implementation would say that
it is from http://www.somesite.com or something like that while the actual
content came from memory.

Sorry for the confusion.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Michael C said:
Interesting. That method was taken largely from an example on the MS
website... Guess they need to fix their samples and use their methods in
a
more correct fashion. Got any examples of code using IPersistMemory?
Noah
Coad published a WebBrowser wrapper control that exposes properties to
assign the HTML directly. His code is at
http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=312. I
don't believe he defines IPersistMemory either.

Thanks,
Michael C., MCDBA


in
message news:[email protected]...
Personally, I wouldn't use that method, as I don't believe it was
intended for this.

Rather, what I would do is define the COM interface IPersistMemory in
your assembly. You can find the definition in Ocidl.idl. Once you have
that, you can cast the value returned from the document property (after you
navigate to about:blank to get an instance loaded) to this interface and
then call Load in order to load the document from memory.

The thing here is that it expects a pointer, in which case, you will
have to copy the content to unmanaged code, or you will have to use
unsafe
code to fix the location of the data in memory and then make the call.

Hope this helps.



Michael C said:
I posted some code to do this already. The post is called "Re:
AxSHDocVw.AxWebBrowser Component Question", the date was 10/9.

Thanks,
Michael C., MCDBA

Hi, Nick,

Could you please show me the code how you can feed html or xml to the web
browser in memory? I can only do it by creating a temp file and supply
the
url. ..

Thanks!
John
in
message Michael,

I don't understand why you wouldn't use the webbrowser? How are you
trying to feed the HTML to it? It's pretty simple, you can do it
through
memory, or through a file, or through a number of other mechanisms.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Anyone know of a good HTML Rendering control? I need a control
that
will
render and display HTML in a Windows form. It doesn't need to pull
down
HTML pages from the Web - I'll feed it all the HTML it needs to
display.
I've already spent way too much time trying to get the Microsoft
WebBrowser
control to work, and I have too many other things to work on to waste
any
more time on it. If you know of any third-party HTML Renderers out
there,
please let me know.

Thanks,
Michael C., MCDBA
 
R

Robert Jordan

Hi Nicholas,
You know, I could have sworn that IPersistMemory was on MSHTML.
Apparently, it is not.

IPersistStreamInit with a stream created with CreateStreamOnHGlobal
sounds like you solution.
I still wouldn't use the writeln function though (although for a quick
fix, I can't say don't use it).

The solution I use (a long time ago) was to fake a moniker and pass it
to the IPersistMoniker interface (the moniker implementation would say that
it is from http://www.somesite.com or something like that while the actual
content came from memory.

That's the recommended way, AFIK.

Using IPersistStreamInit and/or IHTMLDocument2.writeln with
a browser initialized from about:blank will put the browser
in the INTERNET_ZONE (or some other zone != LOCAL_MACHINE,
I cannot recall).
Starting such an app on a Win 2003 server leads to a nasty
security message. Even IInternetSecurityManager doesn't help.

bye
Rob
 
M

Michael C

Code talks, gentlemen.

In Noah Coad's example, he sets the axWebBrowser.Document.body.innerHTML
property for the browser. Is this acceptable? If not, do you have any
examples of acceptable code that you can share?

Thank you,
Michael C., MCDBA
 
R

Robert Jordan

Hi Michael,
In Noah Coad's example, he sets the axWebBrowser.Document.body.innerHTML
property for the browser. Is this acceptable? If not, do you have any
examples of acceptable code that you can share?

body.innerHTML sets, well, only the inner HTML of the body.
If cannot change the HEAD, for example.

The IPersistStreamInit solution:

void Load(string htmlText)
{
IntPtr hMem = Marshal.StringToHGlobalUni(htmlText);
UCOMIStream s;
CreateStreamOnHGlobal(hMem, true, out s);
s.Seek(0, 0, IntPtr.Zero);
IPersistStreamInit p = (IPersistStreamInit)axWebBrowser.Document;
p.InitNew();
p.Load(s);
}

[DllImport("ole32.dll", PreserveSig=false)]
static extern void CreateStreamOnHGlobal(IntPtr hGlobal, bool
fDeleteOnRelease, [Out] out UCOMIStream pStream);

[ComImport]
[Guid("7FD52380-4E07-101B-AE2D-08002B2EC713")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPersistStreamInit
{
void GetClassID([In, Out] ref Guid pClassID);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig] int IsDirty();
void Load([In] UCOMIStream pstm);
void Save([In] UCOMIStream pstm, bool fClearDirty);
void GetSizeMax([Out] long pcbSize);
void InitNew();
}

Anyway, the following warning still applies. I don't have
a IPersistMoniker implementation because I decided to
use local files after I've seen the nasty security message
of the Windows 2003 server ;-)

bye
Rob
 
M

Michael C

For a simple solution, as long as you're not trying to define anything
special in the header, the innerHTML method should be sufficient (assuming
it's not Ratchety[tm]). In fact, you should be able to define JavaScript
functions and CSS StyleSheets inline using the innerHTML. The only reason I
can think of for needing to modify the HEAD is to change the TITLE or if you
have very unique requirements that can only go in the header (i.e., !DOCTYPE
declaration, etc)... Fortunately for my purposes the HEAD, etc., doesn't
really matter :) I like your solution, but there's got to be a way around
the security issues... Is there a way to make the WebBrowser realize it's
coming from the local computer (assuming the local computer is in the
Trusted Zone of course...)? You have me intrigued, and I'm off to research
the IPersistStreamInit solution further. Surprising that they didn't expose
any methods to just set the gosh-darn HTML and be done with it...

Thanks,
Michael C., MCDBA

Robert Jordan said:
Hi Michael,
In Noah Coad's example, he sets the axWebBrowser.Document.body.innerHTML
property for the browser. Is this acceptable? If not, do you have any
examples of acceptable code that you can share?

body.innerHTML sets, well, only the inner HTML of the body.
If cannot change the HEAD, for example.

The IPersistStreamInit solution:

void Load(string htmlText)
{
IntPtr hMem = Marshal.StringToHGlobalUni(htmlText);
UCOMIStream s;
CreateStreamOnHGlobal(hMem, true, out s);
s.Seek(0, 0, IntPtr.Zero);
IPersistStreamInit p = (IPersistStreamInit)axWebBrowser.Document;
p.InitNew();
p.Load(s);
}

[DllImport("ole32.dll", PreserveSig=false)]
static extern void CreateStreamOnHGlobal(IntPtr hGlobal, bool
fDeleteOnRelease, [Out] out UCOMIStream pStream);

[ComImport]
[Guid("7FD52380-4E07-101B-AE2D-08002B2EC713")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPersistStreamInit
{
void GetClassID([In, Out] ref Guid pClassID);
[return: MarshalAs(UnmanagedType.I4)][PreserveSig] int IsDirty();
void Load([In] UCOMIStream pstm);
void Save([In] UCOMIStream pstm, bool fClearDirty);
void GetSizeMax([Out] long pcbSize);
void InitNew();
}

Anyway, the following warning still applies. I don't have
a IPersistMoniker implementation because I decided to
use local files after I've seen the nasty security message
of the Windows 2003 server ;-)

bye
Rob
 
R

Robert Jordan

Hi Michael,
For a simple solution, as long as you're not trying to define anything
special in the header, the innerHTML method should be sufficient (assuming
it's not Ratchety[tm]). In fact, you should be able to define JavaScript
functions and CSS StyleSheets inline using the innerHTML. The only reason I
can think of for needing to modify the HEAD is to change the TITLE or if you
have very unique requirements that can only go in the header (i.e., !DOCTYPE
declaration, etc)... Fortunately for my purposes the HEAD, etc., doesn't

Another drawback of about:blank + innerHTML: you have to use
absolute paths for embedded elements (img, etc.) because
you cannot set up the BASE-element, which has to be adjusted,
otherwise relative paths would by looked up relatively
to about:blank.

IPersistStreamInit has the same limitation but you can
adjust the BASE element, either by injecting the base
into the html string or by injecting an empty base ([base href=""])
and setting it up using the DOM.

bye
Rob
 
N

Nicholas Paldino [.NET/C# MVP]

If you go the route that I specified before, with an implementation of
IMoniker, you can set the base through that. When an implementation of
IMoniker is passed to IPersistMoniker, it uses the value returned from
IMoniker::GetDisplayName as the base for all relative urls.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Robert Jordan said:
Hi Michael,
For a simple solution, as long as you're not trying to define anything
special in the header, the innerHTML method should be sufficient
(assuming it's not Ratchety[tm]). In fact, you should be able to define
JavaScript functions and CSS StyleSheets inline using the innerHTML. The
only reason I can think of for needing to modify the HEAD is to change
the TITLE or if you have very unique requirements that can only go in the
header (i.e., !DOCTYPE declaration, etc)... Fortunately for my purposes
the HEAD, etc., doesn't

Another drawback of about:blank + innerHTML: you have to use
absolute paths for embedded elements (img, etc.) because
you cannot set up the BASE-element, which has to be adjusted,
otherwise relative paths would by looked up relatively
to about:blank.

IPersistStreamInit has the same limitation but you can
adjust the BASE element, either by injecting the base
into the html string or by injecting an empty base ([base href=""])
and setting it up using the DOM.

bye
Rob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top