IEのCOMインターフェイスでSJISとかUTF-8をOnMemoryで表示させる方法
プログラムから(ファイルを使わないで)IEを起動しXMLを開く方法からの派生。
IEのCOMインターフェイスで、OnMemoryからIEで表示する方法としてMSHTML::HTMLDocument2::write(BSTR)を提示したが、BSTRで渡すIFである以上、UNICODE(UTF-16)=WideCharしか渡せないので、SHIFT-JISやUTF-8のようなMultiByteコードで表示できなかった。
これで何が問題になるかというと、inputタグに漢字コードを渡すhiddenなやつがあるとURLエンコードの結果がエンコードに引っ張られてUTF-8のみに固定されてしまったのだ。(なぜUTF-16にならないのかはよくわかっていないが、javascriptがUTF-8前提になっているのでHTML界隈ではUTF-8で扱うことになっているのだろう?)
んで、BSTR型ではない方法で、IEに内容を渡すIFがないのか探していたのだが、(お仕事で実装がほとんど終わったこの時期に)やり方を見つけた。
↓ここを参考にしましたんで、詳細はこちらを参照してください。
Loading HTML content from a Stream
※:GlobalFree()で解放例外が出るなーと思っていたら、CreateStreamOnHGlobal()の第二引数をfalseにしないとダメじゃないですか?
Visual Studio 2017からVisual C++ Win32コンソールアプリケーションから作成(文字セットをUNICODEから設定なしにしておく)。
#include "stdafx.h"
//#include <Strsafe.h>
#include <stdio.h>
#include <tchar.h>
#import <shdocvw.dll>
#import <mshtml.tlb>
bool writeHtml(SHDocVw::IWebBrowser2Ptr &pIE, const TCHAR* pszHTMLText)
{
bool ret = false;
HRESULT hr;
IStream* pStream = NULL;
IDispatch* pHtmlDoc = NULL;
IPersistStreamInit* pPersistStreamInit = NULL;
MSHTML::IHTMLDocument2Ptr pDoc(pIE->Document);
//if (pDoc == nullptr) {
if (pDoc == NULL) {
goto FUNC_END;
}
//size_t cchMax = 256;
size_t cchLength = _tcslen(pszHTMLText);
HGLOBAL hHTMLText = GlobalAlloc(GPTR, cchLength + 1);
if (hHTMLText == NULL) {
goto FUNC_END;
}
//StringCchCopy((TCHAR*)hHTMLText, cchLength + 1, pszHTMLText);
_tcscpy_s((TCHAR*)hHTMLText, cchLength + 1, pszHTMLText);
hr = CreateStreamOnHGlobal(hHTMLText, FALSE, &pStream);
if (FAILED(hr)) {
goto FUNC_END;
}
// Call the helper function to load the browser from the stream.
// Query for IPersistStreamInit.
hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void**)&pPersistStreamInit);
if (FAILED(hr)) {
goto FUNC_END;
}
// Initialize the document.
hr = pPersistStreamInit->InitNew();
if (FAILED(hr)) {
goto FUNC_END;
}
// Load the contents of the stream.
hr = pPersistStreamInit->Load(pStream);
if (FAILED(hr)) {
goto FUNC_END;
}
ret = true;
FUNC_END:
pPersistStreamInit->Release();
pStream->Release();
//pDoc->Release();
pDoc->close();
GlobalFree(hHTMLText);
return ret;
}
// IEを起動してhtmlデータを書き込む
// IEをコントロールしたい(IEを閉じるなど)場合は、WebBrowserのインスタンスを外に出して管理した方がよい
void openIE(const TCHAR* pszHTMLText)
{
SHDocVw::IWebBrowser2Ptr pIE;
// IE 起動+HTMLデータ設定+表示
HRESULT hr = pIE.CreateInstance(__uuidof(SHDocVw::InternetExplorer));
if (FAILED(hr)) {
return;
}
pIE->Navigate(L"about:blank"); //何か設定しないでHTMLを書き込むと例外が発生する。空文字を入れると"http:///"となる
bool bRslt = writeHtml(pIE, pszHTMLText);
if (!bRslt)
{
return;
}
pIE->Visible = VARIANT_TRUE; // IEを表示状態にする。ここで見えるようになる。
pIE = NULL;
}
int main(int argc, char* argv[])
{
int rtn = -1;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwFileSize = 0;
TCHAR* fileData = NULL;
HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (argc != 2) {
fprintf(stderr,
"INVALID ARGUMENT.\n"
" Please Input HTML FileName(FULL PATH).\n"
);
goto FUNC_END;
}
hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
goto FUNC_END;
}
dwFileSize = GetFileSize(hFile, NULL);
fileData = new TCHAR[dwFileSize + 1];
DWORD dwReadSize = 0;
BOOL bRslt = ReadFile(hFile, (LPVOID)fileData, dwFileSize, &dwReadSize, NULL);
if (!bRslt) {
goto FUNC_END;
}
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
fileData[dwFileSize] = '\0';
openIE(fileData);
rtn = 0;
FUNC_END:
if (fileData != NULL) {
delete[]fileData;
}
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
::CoUninitialize();
return rtn;
確認したHTMLファイルは以下。それぞれSHIFT-JISとUTF-8de保存し、引数にファイル名を設定すればOK
なお、UNICODE(UTF-16)で保存されたファイルはNG。
●sjis.html
<html>
<head>
<meta charset="SHIFT_JIS">
</head>
<body>
文字コード:SJIS
</body>
</html>
●utf8.html
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
文字コード:UTF-8
</body>
</html>
« 株:現物売り約定(セブン銀行) | トップページ | 今週届いた本 »
コメント