DHTML应用于windows Applicatoin界面?!讨论!

gameboy999 2003-10-30 09:27:20
开发过基于MFC的windows程序设计的朋友都知道,MFC提供的窗体效果和windows本身一样,无法提供很丰富的表现形式,也没有办法随便更改,
虽然有一些界面组件和界面控件,例如cj60,activeSkin之类的,我觉得也不够灵活。

有没有直接用HTML做界面,利用DHTML内部元素与应用程序交互的可能性呢?我已经看到一些程序使用了这些技术,通过IHTMLDocument接口,通过HTML hook技术来进行交互。

可我很难在网上找到比较详尽的技术介绍,请问大家有什么自己的想法吗?!
大家积极讨论,分大大的有!
...全文
183 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
gameboy999 2003-11-28
  • 打赏
  • 举报
回复
我已经可以用VC6完成消息的绑定,内容的获取,代码如下

/////////////////////////////////////SinkHandler.h//////////////


#include <mshtml.h>
#include <mshtmdid.h>
#include <mshtmhst.h>
#include <atlbase.h>


class CEventSink : IDispatch
{
public:
HRESULT ConnectToConnectionPoint(IUnknown *punkObj, REFIID riid, DWORD *pdwCookie);
void DisconnectFromConnectionPoint(IUnknown *punkObj, REFIID riid, DWORD& dwCookie);
STDMETHOD(CSinkHandlerQueryInterface)(REFIID iid, LPVOID* ppvObj);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);
STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj);
STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
};


/////////////////////////////////////SinkHandler.cpp//////////////

#include "SinkHandler.h"
HRESULT CEventSink::ConnectToConnectionPoint(IUnknown *punkObj, REFIID riid, DWORD *pdwCookie)
{
return AtlAdvise(punkObj, (IDispatch *) this, riid, pdwCookie);
}
void CEventSink::DisconnectFromConnectionPoint(IUnknown *punkObj, REFIID riid, DWORD& dwCookie)
{
AtlUnadvise(punkObj, riid, dwCookie);
}
STDMETHODIMP CEventSink::CSinkHandlerQueryInterface(REFIID iid, LPVOID* ppvObj)
{
if (!ppvObj)
return E_POINTER;

*ppvObj = NULL;
if (IsEqualIID(iid, __uuidof(IDispatch)) || IsEqualIID(iid, __uuidof(IUnknown)))
{
*ppvObj = (IDispatch *) this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP CEventSink::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
return CSinkHandlerQueryInterface(iid,ppvObj);
}
STDMETHODIMP_(ULONG) CEventSink::AddRef()
{
return 1;
}
STDMETHODIMP_(ULONG) CEventSink::Release()
{
return 1;
}
STDMETHODIMP CEventSink::GetTypeInfoCount(UINT *pctinfo)
{
*pctinfo = 0;
ATLTRACENOTIMPL(_T("CEventSink::GetTypeInfoCount"));
}
STDMETHODIMP CEventSink::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
*ppTInfo = NULL;
ATLTRACENOTIMPL(_T("CEventSink::GetTypeInfo"));
}
STDMETHODIMP CEventSink::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
ATLTRACENOTIMPL(_T("CEventSink::GetIDsOfNames"));
}
STDMETHODIMP CEventSink::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
switch ( dispIdMember )
{
case DISPID_HTMLELEMENTEVENTS_ONCLICK:
::MessageBox(NULL,"点击了此处","提示",NULL);
break;
default:
break;
}
return S_OK;
}


//为id为T1的elment增加onclick事件,m_web为webbrowser包装类(classwizzard自动生产)

void CHTMLUIDlg::SetEventHook()
{
HRESULT hr;
IHTMLDocument2 * pDoc2 = NULL;
hr = m_web.GetDocument()->QueryInterface(IID_IHTMLDocument2,(void**)&pDoc2);
if(SUCCEEDED(hr))
{
IHTMLElementCollection* pElemColl = NULL;
hr = pDoc2->get_all(&pElemColl);
if (SUCCEEDED(hr))
{
IDispatch* pElemDisp = NULL;
IHTMLElement* pElem = NULL;
_variant_t varID("T1");
_variant_t varIdx(0l);
hr = pElemColl->item(varID, varIdx, &pElemDisp);
if (SUCCEEDED(hr))
{
hr = pElemDisp->QueryInterface(IID_IHTMLElement, (void**)&pElem);
if (SUCCEEDED(hr))
{
IHTMLInputTextElement * pInputElem;
hr = pElem->QueryInterface(IID_IHTMLInputTextElement,(void**)&pInputElem);
//CComBSTR p("hello world!");
//pInputElem->put_value(p);
ConnectEvents((IHTMLElement *)pInputElem);
pElem->Release();
}
pElemDisp->Release();
}
pElemColl->Release();
}
pDoc2->Release();
}
}

//函数里面的dwCookie其实需要保存下来,用来unadvise用,CEventSink也需要保存下来,记得要delete它. 因演示,所以这里未加处理.

void CHTMLUIDlg::ConnectEvents(IHTMLElement *pElem)
{
HRESULT hr;
IConnectionPointContainer* pCPC = NULL;
IConnectionPoint* pCP = NULL;
DWORD dwCookie;
CEventSink * sink = new CEventSink;
// Check that this is a connectable object.
hr = pElem->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);
if (SUCCEEDED(hr))
{
AfxMessageBox("QueryInterface Successfully!");
// Find the connection point.
hr = pCPC->FindConnectionPoint(DIID_HTMLButtonElementEvents, &pCP);
if (SUCCEEDED(hr))
{
AfxMessageBox("FindConnectionPoint Successfully!");
// Advise the connection point.
hr = pCP->Advise((IUnknown *)sink, &dwCookie);
if (SUCCEEDED(hr))
{
AfxMessageBox("Connect to the Object Successfully!");
}
else
{
if(hr == E_POINTER)
AfxMessageBox("E_POINTER");
if(hr == CONNECT_E_ADVISELIMIT )
AfxMessageBox("CONNECT_E_ADVISELIMIT");
if(hr == CONNECT_E_CANNOTCONNECT )
AfxMessageBox("CONNECT_E_CANNOTCONNECT ");
}
pCP->Release();
}
pCPC->Release();
}
}

gameboy999 2003-11-19
  • 打赏
  • 举报
回复
摘自潘爱民的<<ATL Internals>>书评

在实际应用中,用ActiveX控制或者Windows的标准控制构造新的控制是一项很有用的技术,这就是复合控制,ATL也支持复合控制,它把对话框的功能和ActiveX控制的功能结合起来。在构造复合控制的时候,我们可以指定一个对话框模板,把设计阶段完成的界面模板引入到复合控制中,这是一个非常简便的构造界面单元的方法。
另一个功能更为强大的构造界面单元的方法是HTML控制,它利用Web浏览器控制直接把HTML页面封装成一个新的ActiveX控制。由于它把HTML页面作为界面内容,所以使用的时候非常灵活,我们可以在HTML页面中嵌入脚本,可以使用多种字体,可以访问HTML文档的对象模型。
这一章的内容也比较广泛,但是它把上一章介绍的ActiveX控制与实际的应用结合起来了。而且通过这些内容的介绍,我们可以拓宽视野把ActiveX控制应用得更加灵活,把Web引入到我们的桌面程序上来,或者把桌面程序的功能引入到Web当中去。这两章的内容相对比较独立,它们构成了用ATL开发和使用ActiveX控制的主体。如果读者关注MSJ杂志的话,可以在1999年的2、3、4月期上找到有关这些内容的一个连载,文章的名字为:“Write ActiveX Controls Using Custom Interfaces Provided by ATL 3.0”。
gameboy999 2003-11-07
  • 打赏
  • 举报
回复
to jiangsheng:
是啊,在vc7里面有宏可以将消息映射过来,我打算仔细研究一下看看到底是怎么处理的,并在VC6中实现它。等待我的好消息吧 :)



vc7的代码
HRESULT OnButtonTest(IHTMLElement *pElement);


BEGIN_DHTML_EVENT_MAP(CHTMLUINETDlg)
DHTML_EVENT_ONCLICK(_T("Button1"), OnButtonTest)
END_DHTML_EVENT_MAP()


HRESULT CHTMLUINETDlg::OnButtonTest(IHTMLElement* pElement)
{
CComBSTR p;
pElement->get_tagName(&p);
AfxMessageBox(CString(p));
return S_OK;
}


蒋晟 2003-11-07
  • 打赏
  • 举报
回复
VC7没有class wizzard的确很不方便。比较简单的方法是用MFC的宏,不然自己写处理类实在太麻烦
gameboy999 2003-11-07
  • 打赏
  • 举报
回复
to jiangsheng:
我特意装了.net去看VC7里面的CDHTMLDialog怎么用,发现好像需要自己添加宏来完成HTML到application的绑定,为什么没有了class wizzard呢?

我还是不知道eventsink该怎么写,现在糊里糊涂的



下面是从VC7里面拿来的代码,这个可以用吗?
class CDHtmlEventSink : public CDHtmlSinkHandler
{
public:
HRESULT ConnectToConnectionPoint(IUnknown *punkObj, REFIID riid, DWORD *pdwCookie);
void DisconnectFromConnectionPoint(IUnknown *punkObj, REFIID riid, DWORD& dwCookie);
STDMETHOD(CDHtmlSinkHandlerQueryInterface)(REFIID iid, LPVOID* ppvObj);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);
STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
virtual BOOL DHtmlEventHook(HRESULT *phr, DISPID dispIdMember, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
virtual const DHtmlEventMapEntry* GetDHtmlEventMap() = 0;
virtual HRESULT GetDHtmlDocument(IHTMLDocument2 **pphtmlDoc) = 0;
int FindDHtmlEventEntry(const DHtmlEventMapEntry *pEventMap, DISPID dispIdMember,
IHTMLElement **ppsrcElement);
};

class CDHtmlElementEventSink : public IDispatch
{
public:
CDHtmlEventSink *m_pHandler;
CComPtr<IUnknown> m_spunkElem;
DWORD m_dwCookie;

CDHtmlElementEventSink(CDHtmlEventSink *pHandler, IDispatch *pdisp);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj);
STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);
STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pdispparams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
HRESULT Advise(LPUNKNOWN pUnkObj, REFIID iid);
HRESULT UnAdvise(LPUNKNOWN pUnkObj, REFIID iid);
};
蒋晟 2003-11-06
  • 打赏
  • 举报
回复
每一步都需要检查操作结果和返回的指针
可以用res协议访问
ltbcn 2003-11-06
  • 打赏
  • 举报
回复
学习!!
ablefirst 2003-11-06
  • 打赏
  • 举报
回复
WebBrowser
CHtmlView
ccnuxjg 2003-11-06
  • 打赏
  • 举报
回复
的确,使用Web方式做的确很好,但是安全性真的很头疼。
我不想把页面暴露给用户,但是又没有办法...

我想将页面和页面里用到的css、image、js都做成资源封装在exe程序中,不知是否可行?
tonybaobao 2003-11-06
  • 打赏
  • 举报
回复
学习!!!这才是csdn应该多多看到的帖子。
gameboy999 2003-11-06
  • 打赏
  • 举报
回复
HRESULT hr;
IHTMLDocument2 * pDoc2 = NULL;

// Is this the DocumentComplete event for the top frame window?
// Check COM identity: compare IUnknown interface pointers.
hr = m_web.GetDocument()->QueryInterface(IID_IHTMLDocument2,(void**)&pDoc2);
if(SUCCEEDED(hr))
{
IHTMLElementCollection* pElemColl = NULL;

hr = pDoc2->get_all(&pElemColl);
if (SUCCEEDED(hr))
{

IDispatch* pElemDisp = NULL;
IHTMLElement* pElem = NULL;
_variant_t varID("T1");
_variant_t varIdx(0l);

hr = pElemColl->item(varID, varIdx, &pElemDisp);

if (SUCCEEDED(hr))
{
hr = pElemDisp->QueryInterface(IID_IHTMLElement, (void**)&pElem);

if (SUCCEEDED(hr))
{

IHTMLInputTextElement * pInputElem;
hr = pElem->QueryInterface(IID_IHTMLInputTextElement,(void**)&pInputElem);
BSTR p;
pInputElem->get_value(&p);
AfxMessageBox(CString(p));
pElem->Release();
}
pElemDisp->Release();
}

pElemColl->Release();
}
pDoc2->Release();

}


如果我页面是正常的,那就一切正常

但如果页面是about blank之类的,或找不到服务器之类的,只要一到
hr = pElemDisp->QueryInterface(IID_IHTMLElement, (void**)&pElem);这句
就报错呢?

而且 try也没用,一到这程序马上退出!? 高手点解?
蒋晟 2003-11-06
  • 打赏
  • 举报
回复
Yes
see BEGIN_EVENTSINK_MAP in MFC
gameboy999 2003-11-06
  • 打赏
  • 举报
回复
老外偷懒,用变通的方法来响应事件。。。 --___--!

http://www.chrismaunder.net/shell/dlgdhtmlevents.asp
gameboy999 2003-11-06
  • 打赏
  • 举报
回复
to jiangsheng & all:
看完下面的资料,我的疑问是难道要写一个 com组件并实现IDispatch接口才能完成消息通知的回调吗?



Receiving Element Events


Each element in the DHTML Object Model supports an outgoing HTMLElementEvents2 interface. This interface defines the events that an HTML element can fire. You implement this interface to provide an event sink, which is a Component Object Model (COM) object that implements an outgoing interface and is used as the mechanism for firing events.

Note Interfaces implemented by a server usually have their methods called by the client, but to fire an event, the server calls the respective method on the client event sink. These interface are called outgoing interfaces. A COM object that implements an outgoing interface is also known as a connectable object.
The following steps are required to receive events from an outgoing interface:

Implement the event sink.

The event sink implements the appropriate outgoing interface and methods. Internet Explorer event interfaces are dispinterfaces, so calls to event methods are made through IDispatch::Invoke. This means that you only need to implement the IDispatch interface to handle events.

Determine if the server is a connectable object.

Call QueryInterface to retrieve a pointer to the IConnectionPointContainer interface.

Find the appropriate connection point.

Call the IConnectionPointContainer::FindConnectionPoint method to find the connection point you need. For Internet Explorer WebBrowser Control events, such as DWebBrowserEvents2::DocumentComplete, this is DWebBrowserEvents2. For element events, this is HTMLElementEvents2. You can also call the IConnectionPointContainer::EnumConnectionPoints to enumerate through all the connection points a server supports.

Advise the connection point that you want to receive events.

Using the IConnectionPoint interface pointer returned in the previous step, call IConnectionPoint::Advise, passing the IUnknown interface pointer of your event sink.

Â
Note The connectable object will use the IUnknown interface pointer to query the client for the event sink interface. If the event sink does not support the outgoing interface, Internet Explorer will query the client for the IDispatch interface.
When you no longer want to receive events, you can call the IConnectionPoint::Unadvise method, passing the cookie you received from the call to IConnectionPoint::Advise.
The following sample code demonstrates how to begin receiving HTML element events for an element on an HTML page.

Example:

void CMyClass::ConnectEvents(IHTMLElement* pElem)
{
HRESULT hr;
IConnectionPointContainer* pCPC = NULL;
IConnectionPoint* pCP = NULL;
DWORD dwCookie;

// Check that this is a connectable object.
hr = pElem->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);

if (SUCCEEDED(hr))
{
// Find the connection point.
hr = pCPC->FindConnectionPoint(DIID_HTMLElementEvents2, &pCP);

if (SUCCEEDED(hr))
{
// Advise the connection point.
// pUnk is the IUnknown interface pointer for your event sink
hr = pCP->Advise(pUnk, &dwCookie);

if (SUCCEEDED(hr))
{
// Successfully advised
}

pCP->Release();
}

pCPC->Release();
}
}
The following sample code demonstrates how you would detect the firing of an HTMLElementEvents2::onclick event in your implementation of IDispatch::Invoke.

Example:

STDMETHODIMP CEventSink::Invoke(DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr)
{
switch (dispidMember)
{
case DISPID_HTMLELEMENTEVENTS2_ONCLICK:
OnClick();
break;

default:
break;
}

return S_OK;
}
gameboy999 2003-11-06
  • 打赏
  • 举报
回复
to ccnuxjg:我看到有内存html技术,这样就不会有html在程序外部,但是这样做对只有一个html倒是好说,如果有其他独立的js,css之类的就不方便了。

to ablefirst: 我看到vs.net里面的CDHTMLDialog,确实就是我想要的,但是我不想装vs.net.. CHtmlView并不能让你很好的控制里面的元素,捕获里面的消息啊

to jiangsheng:我能查到错误的地点,但它居然是QueryInterface时候直接报的access violation,虽然这个错误可以通过防止页面出错来避免,但好像还是不方便。


to all:谢谢大家的关注!
我还发现一个很怪的问题,就是一个html页面在IE下面会根据操作系统的不同而不同,例如XP,按钮等会很好看,但是到了我的webbrowser里面,就恢复那种普通的样子,是怎么回事?

还有,border="0"对webbrowser没有用?? 我能通过什么方式来设置它的border=null?

gameboy999 2003-11-05
  • 打赏
  • 举报
回复
我找到我要的东西了。研究中。。。

http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/tutorials/sink.asp

蒋晟 2003-10-30
  • 打赏
  • 举报
回复
sure
Norton Antivirus UI is HTML pages
use CDHtmlDialog for dialog based app and CHtmlView for SDI/MDI
dzqsuper 2003-10-30
  • 打赏
  • 举报
回复
我不会






友情的顶一下吧
kenwhale 2003-10-30
  • 打赏
  • 举报
回复
不懂,,,呵呵,
gameboy999 2003-10-30
  • 打赏
  • 举报
回复
nobody?
加载更多回复(6)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧