2007.07.12 14:49 bruce:
Winform真的是非常方便。
C#写程序也挺好,尤其是微软自己的那些个unicode、ole、com什么的,几行代码替代了以前的一大段。
VS2005窗体控件中已有webBrowser控件,简单的用用还可以。
要发挥ie控件做界面,使cs程序利用上web的好处,还是得自己用activex的浏览器控件
引入axShdocVw。
有些事件,如newwindow3还跟ie版本有关,不然没法编译
光这个还不够,跟以前用c++使用web控件一样,要改变浏览器窗口的形状(去border去滚动条),要调html页面用里面的代码什么的,照样还是需要实现IDocHostUIHandler
将ie控件本身的父窗口Shell DocObject View做的事情接管过来。
具体做法:
codeproject上早有源码,也有老外封装过的控件
翻译过的挺清楚 http://www.vckbase.com/document/viewdoc/?id=1018
1:写个MsHtmHstInterop.idl
[
uuid(47F05070-FD66-45cc-AD99-74260F94A16B)
]
library MsHtmHstInterop
{
import "MsHtmHst.idl";
enum tagDOCHOSTUIDBLCLK;
enum tagDOCHOSTUIFLAG;
enum tagDOCHOSTUITYPE;
interface ICustomDoc;
interface IDocHostShowUI;
interface IDocHostUIHandler;
interface IDocHostUIHandler2;
interface IHostDialogHelper;
};
2:在“Visual Studio 2005 命令提示”的CMD环境下,将idl转成可用的dll
midl MsHtmHstInterop.idl /tlb bin\MsHtmHstInterop.tlb
tlbimp bin\MsHtmHstInterop.tlb /out:bin\MsHtmHstInterop.dll
3:将dll引入工程
4:在窗口类最上面引用
using mshtml;
using MsHtmHstInterop;
一定要放在顶部
5:实现接口
就在自己的窗口类后加, IDocHostUIHandler
// IDocHostUIHandler Implementations
void IDocHostUIHandler.EnableModeless(int fEnable)
{
}
void IDocHostUIHandler.FilterDataObject(MsHtmHstInterop.IDataObject pDO, out MsHtmHstInterop.IDataObject ppDORet)
{
ppDORet = null;
}
void IDocHostUIHandler.GetDropTarget(MsHtmHstInterop.IDropTarget pDropTarget, out MsHtmHstInterop.IDropTarget ppDropTarget)
{
ppDropTarget = null;
}
void IDocHostUIHandler.GetExternal(out object ppDispatch)
{
// ppDispatch = new PopulateClass(this);
ppDispatch = null;
}
void IDocHostUIHandler.GetHostInfo(ref _DOCHOSTUIINFO pInfo)
{
pInfo.dwFlags |= (0x08/*DOCHOSTUIFLAG_SCROLL_NO*/|0x04/*DOCHOSTUIFLAG_NO3DBORDER*/
);
}
void IDocHostUIHandler.GetOptionKeyPath(out string pchKey, uint dw)
{
pchKey = null;
}
void IDocHostUIHandler.HideUI()
{
}
void IDocHostUIHandler.OnDocWindowActivate(int fActivate)
{
}
void IDocHostUIHandler.OnFrameWindowActivate(int fActivate)
{
}
void IDocHostUIHandler.ResizeBorder(ref MsHtmHstInterop.tagRECT prcBorder, IOleInPlaceUIWindow pUIWindow, int fRameWindow)
{
}
void IDocHostUIHandler.ShowContextMenu(uint dwID, ref MsHtmHstInterop.tagPOINT ppt, object pcmdtReserved, object pdispReserved)
{
throw new COMException("", 1);
}
void IDocHostUIHandler.ShowUI(uint dwID, IOleInPlaceActiveObject pActiveObject, IOleCommandTarget pCommandTarget, IOleInPlaceFrame pFrame, IOleInPlaceUIWindow pDoc)
{
}
void IDocHostUIHandler.TranslateAccelerator(ref tagMSG lpmsg, ref Guid pguidCmdGroup, uint nCmdID)
{
}
void IDocHostUIHandler.TranslateUrl(uint dwTranslate, ref ushort pchURLIn, IntPtr ppchURLOut)
{
}
void IDocHostUIHandler.UpdateUI()
{
}
6:将浏览器的UIHandel设进来。在Load事件中做
ICustomDoc cDoc = (ICustomDoc)this.axWebBrowser.Document;
cDoc.SetUIHandler((IDocHostUIHandler)this);
这里一定注意,设置之前,document必须是创建了的,如果不navigate的话就setUIHandle就会出错。
一般做法设置前,先导航到空页面。
object flags = 0;
object targetFrame = String.Empty;
object postData = String.Empty;
object headers = String.Empty;
this.axWebBrowser.Navigate("about:blank", ref flags, ref targetFrame, ref postData, ref headers);
然后就在那几个实现的方法中加代码即可。
比如去边框,去滚动条以达到和主界面协调:
void IDocHostUIHandler.GetHostInfo(ref _DOCHOSTUIINFO pInfo)
{
pInfo.dwFlags |= (0x08/*DOCHOSTUIFLAG_SCROLL_NO*/|0x04/*DOCHOSTUIFLAG_NO3DBORDER*/
);
}
这些个DOCHOSTUIFLAG_SCROLL_NO定义都只能在SDK装了以后才有,所以具体的值啊技巧啊,还是得网上搜和查看SDK
——————2007.7.13
和C++不同,这些个接口没返回值,不想捕获一些事件的话没法通过返回值控制。
只能抛异常出去throw new COMException(“”, 1);
void IDocHostUIHandler.ShowContextMenu(uint dwID, ref MsHtmHstInterop.tagPOINT ppt, object pcmdtReserved, object pdispReserved)//不捕获右键菜单
{
throw new COMException("", 1);
}
void IDocHostUIHandler.TranslateAccelerator(ref tagMSG lpmsg, ref Guid pguidCmdGroup, uint nCmdID)//不捕获按键事件
{
throw new COMException("", 1);
}
const int Ok = 0;
const int Error = 1;
// use one of the following statements
throw new COMException("", Ok); // HRESULT returned: S_OK
throw new COMException("", Error); // HRESULT returned: S_FALSE
——————问题
weishijun说 SetUIHandler((IDocHostUIHandler)this); 不是好方法,但有的例子代码都是MFC的。
确实,没回必须先定向到一个有边框有滚动条的about:blank页面,才能跳转过去,效果很差,应该在构造的时候就指定了hostsite
因为是先有了doc才能重订向handler
应该跟chtmlview一样,构造的时候就可以设定。
现在的效果就是:一开始很明显有border和滚动条,然后从定向后就没了。
这篇才叫详细:http://www.codeproject.com/books/0764549146_8.asp
需要指定ole容器,而不是设定IDocHostUIHandler的SetUIHandler
而且旧的那种方法有内存泄露
因此必须先指定
object obj = axWebBrowser1.GetOcx();
IOleObject oc = obj as IOleObject;
oc.SetClientSite(this);
因此要实现 IOleClientSite
这个接口定义又得一顿好找。
那个文中说 VC目录下的平台sdk的include目录下有idl的定义。
还是麻烦
后来,直接在第一步写MsHtmHstInterop.idl的时候增加2个接口,直接发布就好了。
[
uuid(47F05070-FD66-45cc-AD99-74260F94A16B)
]
library MsHtmHstInterop
{
import "MsHtmHst.idl";
enum tagDOCHOSTUIDBLCLK;
enum tagDOCHOSTUIFLAG;
enum tagDOCHOSTUITYPE;
interface ICustomDoc;
interface IDocHostShowUI;
interface IDocHostUIHandler;
interface IDocHostUIHandler2;
interface IHostDialogHelper;
interface IOleObject;
interface IOleClientSite;
};
实现一些空接口后
void IOleClientSite.GetContainer(out IOleContainer ppContainer)
{
ppContainer = null;
}
void IOleClientSite.GetMoniker(uint dwAssign, uint dwWhichMoniker, out IMoniker ppmk)
{
ppmk = null;
}
void IOleClientSite.OnShowWindow(int fShow)
{
}
void IOleClientSite.RequestNewObjectLayout()
{
}
void IOleClientSite.SaveObject()
{
}
void IOleClientSite.ShowObject()
{
}
然后在 InitializeComponent();后,直接设置ClientSite
object obj = this.axWebBrowser.GetOcx();
IOleObject oc = obj as IOleObject;
oc.SetClientSite(this);
——————2007.7.14
让webbrowser控件内显示的html支持XP皮肤 XP themed
这个也详尽http://www.codeproject.com/cs/miscctrl/WebBrowserEx.asp
也就是在GetHostInfo()中设置一下
if (wbUseXPTheme){//使用XP
pInfo.dwFlags |= (int)DOCHOSTUIFLAG.DOCHOSTUIFLAG_THEME;// 0x08;/*DOCHOSTUIFLAG_THEME*/
}
所有属性如下:
internal enum DOCHOSTUIFLAG
{
DOCHOSTUIFLAG_DIALOG = 0x00000001,
DOCHOSTUIFLAG_DISABLE_HELP_MENU = 0x00000002,
DOCHOSTUIFLAG_NO3DBORDER = 0x00000004,
DOCHOSTUIFLAG_SCROLL_NO = 0x00000008,
DOCHOSTUIFLAG_DISABLE_SCRIPT_INACTIVE = 0x00000010,
DOCHOSTUIFLAG_OPENNEWWIN = 0x00000020,
DOCHOSTUIFLAG_DISABLE_OFFSCREEN = 0x00000040,
DOCHOSTUIFLAG_FLAT_SCROLLBAR = 0x00000080,
DOCHOSTUIFLAG_DIV_BLOCKDEFAULT = 0x00000100,
DOCHOSTUIFLAG_ACTIVATE_CLIENTHIT_ONLY = 0x00000200,
DOCHOSTUIFLAG_OVERRIDEBEHAVIORFACTORY = 0x00000400,
DOCHOSTUIFLAG_CODEPAGELINKEDFONTS = 0x00000800,
DOCHOSTUIFLAG_URL_ENCODING_DISABLE_UTF8 = 0x00001000,
DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8 = 0x00002000,
DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE = 0x00004000,
DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION = 0x00010000,
DOCHOSTUIFLAG_IME_ENABLE_RECONVERSION = 0x00020000,
DOCHOSTUIFLAG_THEME = 0x00040000,
DOCHOSTUIFLAG_NOTHEME = 0x00080000,
DOCHOSTUIFLAG_NOPICS = 0x00100000,
DOCHOSTUIFLAG_NO3DOUTERBORDER = 0x00200000,
DOCHOSTUIFLAG_DELEGATESIDOFDISPATCH = 0x00400000
}
——————对控件内的html元素进行操作:
IHTMLDocument2 doc = (IHTMLDocument2)this.axWebBrowser.Document;
然后使用HTMLInputTextElement等查找dhtml中的对象,然后进行操作
得在 DocumentComplete事件后响应
