查看文章
 
[已提供源码下载]WebGUIFramework - 让Web表现层技术与C++搭档 - VC + HTML + JS
2009年07月24日 星期五 下午 11:12

    酝酿了挺长一段时间了,大约有半年了,不过网上这方面的资料已经很多了,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;

 


类别:Webguiframework||添加到搜藏 |分享到i贴吧|浏览(5279)|评论 (0)
 
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu