‘店大欺人’這句話放在哪里都適用,瀏覽器市場(chǎng)亦是如此。IE當(dāng)?shù)溃渌鼮g覽器如若顯示跟其不一致,往往會(huì)被打上‘不標(biāo)準(zhǔn)’的烙記,也迫使HTML使用者不得不用IE來(lái)檢測(cè)是否符合‘標(biāo)準(zhǔn)’。真的很杯具,且不說IE自己定義了大量‘不標(biāo)準(zhǔn)’的Tag,誰(shuí)又能確定IE對(duì)標(biāo)準(zhǔn)的執(zhí)行本身是否‘標(biāo)準(zhǔn)’呢?平常我用Google Chrome,但寫B(tài)log時(shí)還是需要切換到IE上,誰(shuí)叫這些控件都是依據(jù)IE作為‘標(biāo)準(zhǔn)’的。這也是沒有辦法的事情,畢竟IE曾經(jīng)太強(qiáng)大了,致使現(xiàn)在依然余威不散啊。。。
扯遠(yuǎn)了,我就來(lái)發(fā)發(fā)牢騷了,實(shí)際想說的是,為了讓LingosHook的HTML展示更接近Lingoes的顯示,這幾天不得不在嘗試讓LingosHook也支持適用IE來(lái)顯示結(jié)果,誰(shuí)叫Lingoes用IE呢。。
下面輕松一下,做個(gè)GAME--看圖找不同。。


是的,還是第二張圖的顯示比較好看~第一張圖是使用wxWidget自帶的wxHtmlWin控件顯示的,而第二張則是通過Activx調(diào)用IE控件顯示的。
wxWidget下封裝IE控件,能直接找到的就是wxActivex (這個(gè)就是常說的wxIE)了,雖然控件本身老是老了點(diǎn),2005年發(fā)布的,但依然很好用--當(dāng)然了,為了在wxWidget2.8下編譯,為了支持中文顯示,還是需要做一些修改的。
如何在wxWidget2.8下編譯,這個(gè)問題改改并不難,就不說了,就單說說這個(gè)中文顯示問題吧。wxActivex使用LoadString()來(lái)顯示內(nèi)存中的字符串,實(shí)現(xiàn)如下:
bool wxIEHtmlWin::LoadString(const wxString& html)


{
char *data = NULL;
size_t len = html.length();
#ifdef UNICODE
len *= 2;
#endif
data = (char *) malloc(len);
memcpy(data, html.c_str(), len);

return LoadStream(new wxOwnedMemInputStream(data, len));
};
如果變量html中的字符都是char類型也沒啥問題,memcpy一下就OK,但如果是wchar_t寬字節(jié)類型,就不能單單調(diào)用一下memcpy了,這個(gè)涉及到寬字節(jié)到多字節(jié)(WC->MB)的問題了。于是照著葫蘆畫瓢,添加了如下代碼,這個(gè)問題就過了。。。。
class IStreamFromWString : public IStream


{
private:
DECLARE_OLE_UNKNOWN(IStreamFromWString);

public:
IStreamFromWString(const wxString& str)
: _buffer(NULL), _sz(0), _pos(0)

{
InitBuffer(str);
}
virtual ~IStreamFromWString()

{
FreeBuffer();
}
// ISequentialStream
HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead)

{
if(_pos >= _sz)

{
(*pcbRead) = 0;
return S_OK;
}

if((_pos + cb) < _sz)

{
memcpy((void*)pv, (void*)(_buffer + _pos), cb);
(*pcbRead) = cb;
_pos += cb;
return S_OK;
}
else

{
memcpy((void*)pv, (void*)(_buffer + _pos), _sz - _pos);
(*pcbRead) = (_sz - _pos);
_pos = _sz;
return S_OK;
}
};

// IStream

HRESULT STDMETHODCALLTYPE Write(const void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbWritten)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER __RPC_FAR *plibNewPosition)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE CopyTo(IStream __RPC_FAR *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER __RPC_FAR *pcbRead, ULARGE_INTEGER __RPC_FAR *pcbWritten)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE Revert(void)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE Stat(STATSTG __RPC_FAR *pstatstg, DWORD grfStatFlag)
{return E_NOTIMPL;}

HRESULT STDMETHODCALLTYPE Clone(IStream __RPC_FAR *__RPC_FAR *ppstm)
{return E_NOTIMPL;}
private:
void InitBuffer(const wxString& str)

{
_sz = wxConvUTF8.FromWChar(NULL, 0, str.c_str(), str.size());
_buffer = new char[_sz];
wxConvUTF8.FromWChar(_buffer, _sz, str.c_str(), str.size());
//int codepage = 54936;//CP_UTF8;

//int sz = WideCharToMultiByte(codepage, 0, html.c_str(), html.size(), NULL, 0, NULL, NULL);
//if(sz == -1)
// return -1;
//char* buf = new char[sz + 1];
//sz = WideCharToMultiByte(codepage, 0, html.c_str(), html.size(), buf, sz, NULL, NULL);
}
void FreeBuffer()

{
if(_buffer != NULL)
delete [] _buffer;
}
private:
char * _buffer;
size_t _sz;
size_t _pos;
};

DEFINE_OLE_TABLE(IStreamFromWString)
OLE_IINTERFACE(IUnknown)
OLE_IINTERFACE(ISequentialStream)
OLE_IINTERFACE(IStream)
END_OLE_TABLE;

bool wxIEHtmlWin::LoadWString(const wxString& html)


{
IDispatch *pDisp = NULL;
HRESULT hret = m_webBrowser->get_Document(&pDisp);
if (!pDisp)
return false;
wxAutoOleInterface<IDispatch> disp(pDisp);
// get IPersistStreamInit
wxAutoOleInterface<IPersistStreamInit> pPersistStreamInit(IID_IPersistStreamInit, disp);

if (pPersistStreamInit.Ok())

{
HRESULT hr = pPersistStreamInit->InitNew();

if (SUCCEEDED(hr))

{
CComPtr<IStream> is(new IStreamFromWString(html));
hr = pPersistStreamInit->Load(is);
}

return SUCCEEDED(hr);
}
else
return false;
}

可以看出,也沒做什么,就是調(diào)用一下類似WideCharToMultiByte()就OK了。編碼LingosHook的過程中,最讓我感慨的事就是--原來(lái)char到wchar_t、string到wstring是如此的繁瑣,陷阱重重。。。唉,一切都是charset引起的,要是當(dāng)年ASCII設(shè)計(jì)者們有點(diǎn)‘國(guó)際主義’精神,直接用定義出Unicode多好,哪有中間這么多charset的問題。。。(發(fā)牢騷而已,誰(shuí)也不是先知。。。)
另外定義了個(gè)宏__LH_USE_IE__,用于編譯期切換所使用的控件,不喜歡IE的,可以繼續(xù)使用wxHtmlWin,嘿嘿,要留好‘革命的火種’啊。。。
#ifdef __LH_USE_WXIE__

#include "IEHtmlWin.h"

class CLHHtmlWindow : public wxIEHtmlWin


{
public:
CLHHtmlWindow(wxWindow * parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr)
: wxIEHtmlWin(parent, id, pos, size, style, name)

{
}

virtual ~CLHHtmlWindow()
{}

public:

void LoadBlankPage()
{ wxIEHtmlWin::LoadWString(wxT("<HTML></HTML>")); }

bool LoadString(const wxString& html)
{ return wxIEHtmlWin::LoadWString(html); }

void SetCharset(const wxString& charset)
{ wxIEHtmlWin::SetCharset(charset); }
};

#else

#include <wx/html/htmlwin.h>

class CLHHtmlWindow : public wxHtmlWindow


{
public:
CLHHtmlWindow(wxWindow * parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr)
: wxHtmlWindow(parent, id, pos, size, style, name)

{
}

virtual ~CLHHtmlWindow()
{}

public:

void LoadBlankPage()
{ wxHtmlWindow::SetPage(wxT("<HTML></HTML>")); }
bool LoadString(const wxString& html)

{
wxString str = html;
str.Replace(_("file:///"), _(""), true);
return wxHtmlWindow::SetPage(str);
}

void SetCharset(const wxString& charset)
{}
};

#endif