
酝酿了挺长一段时间了,大约有半年了,不过网上这方面的资料已经很多了,VC搞的界面挺让人郁闷,界面库其实有不少,不过很多要花钱,免费的控件重绘不全,最主要的原因是界面修改不够灵活,不过可能是本人技术不到家造成的
。
以前写过一篇CDHtmlDialog中屏蔽不安全ActiveX控件提示的文章,主要方法就是实现COleControlSite的派生类,然后实现IInternetSecurityManager接口,本次开发算是在上次的基础上完善了COleControlSite派生类,目前实现的接口如下:
INewWindowManager
IHTMLOMWindowServices
IDocHostShowUI
IDocHostUIHandler
IInternetSecurityManager
IServiceProvider
这些接口的实现思路,都是参考自定义浏览器开发一类的文章写成,网上很容易搜到,本人也搞不清楚谁是原作者,就不在这里给出链接了。
这个小东东的名字暂定为:WebGUIFramework,开发语言C++,环境VC2005,是一个基于CDHtmlDialog的对话框的项目,软件的核心ColeControlSite派生类参考了微软的示例代码,如下URL:
微软的参考:http://support.microsoft.com/kb/246227/en-us
目的是寻求一个可以利用Web技术做软件表现层的通用方法,CDHtmlDialog本身包含了对IWebBrowser2的实现,就是常说的浏览器控件,可能做VB、C#的朋友们对它比较熟悉,可以让一个窗口显示网页,算是个内嵌的浏览器,本项目就是想利用IE的内核来处理Web的表现层,这样我们就可以用简单的HTML、CSS来做界面了,并且修改方便,更重要的是资源丰富,Web程序员众多,还能从别人网站上借鉴界面代码
,另一个原因是有脚本引擎,JavaScript和VBScript可供我们使用,用Flash的兄弟也没什么障碍。
对于一些核心业务逻辑的代码,或者不方便给大家看的代码,打算以DLL扩展的方式接入到WebGUIFramework中,让表现层与其交互,做到物质文明和精神文明共同发展
,这里利用了IDocHostUIHandler::GetExternal()方法,脚本可以通过window.external连接到自定义的扩展,贴代码吧,估计还是代码来的明白:
STDMETHODIMP CCustomControlSite::XDocHostUIHandler::GetExternal(
/* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
{
METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler)
//返回自定义的扩展对象
return myExt.GetExternal(ppDispatch);
}
而myExt是这样定义的:class CMyExternal : public CCmdTarget,然后重写CCmdTarget的GetExternal()方法:
HRESULT CMyExternal::GetExternal(LPDISPATCH *lppDispatch)
{
if(lppDispatch == NULL)
{
return E_POINTER;
}
//返回自身的IDispatch接口
*lppDispatch = GetIDispatch(TRUE);
return S_OK;
}
在CMyExternal中,使用DISPATCH_MAP宏定义提供几个接口:
BEGIN_DISPATCH_MAP(CMyExternal, CCmdTarget)
DISP_FUNCTION(CMyExternal, "TestFunc", TestFunc, VT_BOOL, VTS_BSTR VTS_I4)
DISP_FUNCTION(CMyExternal, "GetExt", GetExt, VT_DISPATCH, VTS_BSTR)
DISP_FUNCTION(CMyExternal, "GetWebGUIFrameWnd", GetWebGUIFrameWnd, VT_DISPATCH, VTS_NONE)
DISP_FUNCTION(CMyExternal, "DelayMs", DelayMs, VT_EMPTY, VTS_I4)
END_DISPATCH_MAP();
GetWebGUIFrameWnd提供CDHtmlDialog派生类的IDispatch指针,用来控制窗口的行为和外观,如
//禁用窗口最大化按钮,后面改为true就恢复正常
external.GetWebGUIFrameWnd().ModifyStyle(WS_MAXIMIZEBOX, false);
//禁止用鼠标改变窗口大小,同样后面改为true就恢复正常
external.GetWebGUIFrameWnd().ModifyStyle(WS_SIZEBOX, false);
详细说一下GetExt()方法,这个方法是脚本调用外部DLL的桥梁,看下面的示例代码:
set vb_example = external.GetExt("ExampleExt")
num_sum = vb_example.TestAdd(1, 2)
ExampleExt是一个外部DLL扩展,external.GetExt()返回扩展DLL的IDispatch指针供脚本使用,所以扩展DLL无需注册到系统,只要将内部的IDispatch指针暴露出来即可,WebGUIFramework通过LoadLibaray()和FreeLibaray()管理扩展DLL,以便获取最大的灵活性。
GetExt()实现代码:
LPDISPATCH CMyExternal::GetExt(LPCSTR lpszExtName)
{
//m_lpDispSet是一个IDispatch指针集合
map<string, ExtModuleInfo *>::const_iterator it = m_lpDispSet.find(string(lpszExtName));
if (it == m_lpDispSet.end())
{
return NULL;
}
else
{
it->second->lpDisp->AddRef();
return it->second->lpDisp;
}
}
至于如何加载、卸载DLL,就不再这里浪费大家的心情了。
至于其他的接口,如IDocHostShowUI::ShowMessage(),也是学习网友例程,大家去搜搜就行。
最终生成的是一个WebGUIFramework.exe文件,它还处理了命令行参数载入首页,遍历当前目录中所有DLL并调用其LPDISPATCH WINAPI GetIDispatchPtr()导出函数,载入DLL内部的IDispatch指针,剩下的开发工作将由Web程序员、扩展DLL程序员配合完成。
Web程序员可以用DIV+CSS来构架自己的界面,用JQuery来做做JavaScript,弄个Flash炫一炫,当然了,正如大伦子说的那样,效率是我们应该考虑的一个重要问题,毕竟是Web啊。
扩展DLL的写法很简单,建立标准的DLL,提供一个LPDISPATCH WINAPI GetIDispatchPtr()函数,内部可以用CCmdTarget来实现,这样写起来比较简单。
可能还有不少人想用C++调用JavaScript,这个不难,找个时间实现出来,主要通过IHTMLWindow2::execScript()来处理,目前我就看好这个方法。
不多说了,下面把我实现的所有的接口列个表,并提供一个示例的下载地址,今天刚刚建了版本库,源代码目前乱得没法见人,整理后再提供下载:
http://yuyuyouer.cn/down/WebGUIFrameWork_DEMO_v01.zip
解压工具:http://www.7-zip.org/
////////////////////////////////
//// Implement IHTMLOMWindowServices
//// window.moveTo/By、window.resizeTo/By
BEGIN_INTERFACE_PART(HTMLOMWindowServices, IHTMLOMWindowServices)
INIT_INTERFACE_PART(CCustomControlSite, HTMLOMWindowServices)
STDMETHOD(moveTo)(
/* [in] */ LONG x,
/* [in] */ LONG y);
STDMETHOD(moveBy)(
/* [in] */ LONG x,
/* [in] */ LONG y);
STDMETHOD(resizeTo)(
/* [in] */ LONG x,
/* [in] */ LONG y);
STDMETHOD(resizeBy)(
/* [in] */ LONG x,
/* [in] */ LONG y);
END_INTERFACE_PART(HTMLOMWindowServices)
////////////////////////////////
//// Implement IDocHostShowUI
//// alert("定制消息框标题");
BEGIN_INTERFACE_PART(DocHostShowUI, IDocHostShowUI)
INIT_INTERFACE_PART(CCustomControlSite, DocHostShowUI)
STDMETHOD(ShowHelp)(
/* [in ] */ HWND hwnd,
/* [in ] */ LPOLESTR pszHelpFile,
/* [in ] */ UINT uCommand,
/* [in ] */ DWORD dwData,
/* [in ] */ POINT ptMouse,
/* [out] */ IDispatch __RPC_FAR *pDispatchObjectHit);
STDMETHOD(ShowMessage)(
/* [in ] */ HWND hwnd,
/* [in ] */ LPOLESTR lpstrText,
/* [in ] */ LPOLESTR lpstrCaption,
/* [in ] */ DWORD dwType,
/* [in ] */ LPOLESTR lpstrHelpFile,
/* [in ] */ DWORD dwHelpContext,
/* [out] */ LRESULT __RPC_FAR *plResult);
END_INTERFACE_PART(DocHostShowUI)
////////////////////////////////
////Implement IDocHostUIHandler
////东西不少,GetExt()、GetHostInfo()、ShowContextMenu()等
BEGIN_INTERFACE_PART(DocHostUIHandler, IDocHostUIHandler)
INIT_INTERFACE_PART(CCustomControlSite, DocHostUIHandler)
STDMETHOD(ShowContextMenu)(/* [in] */ DWORD dwID,
/* [in] */ POINT __RPC_FAR *ppt,
/* [in] */ IUnknown __RPC_FAR *pcmdtReserved,
/* [in] */ IDispatch __RPC_FAR *pdispReserved);
STDMETHOD(GetHostInfo)(
/* [out][in] */ DOCHOSTUIINFO __RPC_FAR *pInfo);
STDMETHOD(ShowUI)(
/* [in] */ DWORD dwID,
/* [in] */ IOleInPlaceActiveObject __RPC_FAR *pActiveObject,
/* [in] */ IOleCommandTarget __RPC_FAR *pCommandTarget,
/* [in] */ IOleInPlaceFrame __RPC_FAR *pFrame,
/* [in] */ IOleInPlaceUIWindow __RPC_FAR *pDoc);
STDMETHOD(HideUI)(void);
STDMETHOD(UpdateUI)(void);
STDMETHOD(EnableModeless)(/* [in] */ BOOL fEnable);
STDMETHOD(OnDocWindowActivate)(/* [in] */ BOOL fEnable);
STDMETHOD(OnFrameWindowActivate)(/* [in] */ BOOL fEnable);
STDMETHOD(ResizeBorder)(
/* [in] */ LPCRECT prcBorder,
/* [in] */ IOleInPlaceUIWindow __RPC_FAR *pUIWindow,
/* [in] */ BOOL fRameWindow);
STDMETHOD(TranslateAccelerator)(
/* [in] */ LPMSG lpMsg,
/* [in] */ const GUID __RPC_FAR *pguidCmdGroup,
/* [in] */ DWORD nCmdID);
STDMETHOD(GetOptionKeyPath)(
/* [out] */ LPOLESTR __RPC_FAR *pchKey,
/* [in] */ DWORD dw);
STDMETHOD(GetDropTarget)(
/* [in] */ IDropTarget __RPC_FAR *pDropTarget,
/* [out] */ IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget);
STDMETHOD(GetExternal)(
/* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch);
STDMETHOD(TranslateUrl)(
/* [in] */ DWORD dwTranslate,
/* [in] */ OLECHAR __RPC_FAR *pchURLIn,
/* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut);
STDMETHOD(FilterDataObject)(
/* [in] */ IDataObject __RPC_FAR *pDO,
/* [out] */ IDataObject __RPC_FAR *__RPC_FAR *ppDORet);
END_INTERFACE_PART(DocHostUIHandler)
///////////////////////////////////////
////Implement IInternetSecurityManager
////ProcessUrlAction()
BEGIN_INTERFACE_PART(InternetSecurityManager, IInternetSecurityManager)
INIT_INTERFACE_PART(CCustomControlSite, InternetSecurityManager)
STDMETHOD(SetSecuritySite)(IInternetSecurityMgrSite*);
STDMETHOD(GetSecuritySite)(IInternetSecurityMgrSite**);
STDMETHOD(MapUrlToZone)(LPCWSTR,DWORD*,DWORD);
STDMETHOD(GetSecurityId)(LPCWSTR,BYTE*,DWORD*,DWORD);
STDMETHOD(ProcessUrlAction)(
/* [in] */ LPCWSTR pwszUrl,
/* [in] */ DWORD dwAction,
/* [size_is][out] */ BYTE __RPC_FAR *pPolicy,
/* [in] */ DWORD cbPolicy,
/* [in] */ BYTE __RPC_FAR *pContext,
/* [in] */ DWORD cbContext,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwReserved = 0);
STDMETHOD(QueryCustomPolicy)(LPCWSTR,REFGUID,BYTE**,DWORD*,BYTE*,DWORD,DWORD);
STDMETHOD(SetZoneMapping)(DWORD,LPCWSTR,DWORD);
STDMETHOD(GetZoneMappings)(DWORD,IEnumString**,DWORD);
END_INTERFACE_PART(InternetSecurityManager)
///////////////////////////////////////
//// Implement IServiceProvider
BEGIN_INTERFACE_PART(ServiceProvider, IServiceProvider)
INIT_INTERFACE_PART(CCustomControlSite, ServiceProvider)
STDMETHOD(QueryService)(REFGUID,REFIID,void**);
END_INTERFACE_PART(ServiceProvider)
///////////////////////////////////////
////Implement INewWindowManager
BEGIN_INTERFACE_PART(NewWindowManager, INewWindowManager)
INIT_INTERFACE_PART(CCustomControlSite, NewWindowManager)
STDMETHOD(EvaluateNewWindow)(
/* [in] */ LPCWSTR pszUrl,
/* [in] */ LPCWSTR pszName,
/* [in] */ LPCWSTR pszUrlContext,
/* [in] */ LPCWSTR pszFeatures,
/* [in] */ BOOL fReplace,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwUserActionTime);
END_INTERFACE_PART(NewWindowManager)
WebGUIFramework_DEMO下载:
http://yuyuyouer.cn/down/WebGUIFrameWork_DEMO_v01.zip
解压工具:http://www.7-zip.org/
==========================================================
源码包下载:
http://www.yuyuyouer.cn/down/WebGUIFramework_svnr29.zip
==========================================================
更新记录:
编译环境从VC2005变为VC2008,这里需要浏览器最低版本IE6 SP2;