2021年08月28日

LuaAppMaker: Windows の日本語パス名で大苦戦(つづき)

 「LuaAppMaker: Windows の日本語パス名で大苦戦」のつづきです。ヘルプを wxWebView で表示しようと思ったわけですよ。wxHTML とか Help Book 形式よりカッコいいし、自由度も高い。外部ブラウザを立ち上げないで済めば、ユーザー側も使いやすい。こんな風に使います。なんでプレフィックスが wx じゃなくて wxwebview なのかは謎ですが。いちいちタイプ数が多くなるやんか。

  local helpFrame = wx.wxFrame(wx.NULL, -1, "Help", wx.wxDefaultPosition, wx.wxDefaultSize)
  local webview = wxwebview.wxWebView.New(helpFrame, -1, "", wx.wxDefaultPosition, wx.wxSize(width, 600), wxwebview.wxWebViewBackendDefault, 0, "")
  local sizer = wx.wxBoxSizer(wx.wxHORIZONTAL)
  sizer:Add(webview, 1, wx.wxALL + wx.wxEXPAND, 0)
  helpFrame:SetSizerAndFit(sizer)
  webview:LoadURL(url)
  helpFrame:Show(true)

 問題は LoadURL() に渡す文字列です。まさか、インターネットにつながってないとヘルプが見られない、なんて設計はあり得ませんから(最近のアプリはそういうの平気ですが、私は嫌いです)、アプリに内蔵した html ファイルのパスを渡すことになる。日本語を含むパス上にアプリを置いてある場合は、日本語を含む文字列になる。Mac だったら、UTF-8 でパーセントエンコードすれば済みますが、Windows 版の wxWebView のベースになるのは IE です。そう簡単に済むはずもない。調査開始です。なお、わざと悪条件を設定して、IE 8 が動いている Windows 7 でテストしています。

 まず、URL をパーセントエンコードして LoadURL() に渡してみた。これはダメで、真っ白のウィンドウが開いてしまう。UTF-8 でも Shift-JIS でもダメ。

 次に、日本語文字を含んだままで LoadURL() に渡してみる。一応ページは開くけど、下のエラーが出る。例外を投げてしまうので、これ以上処理を継続できない。

../src/common/unichar.cpp(65): assert "Assert failure" failed in ToHi8bit(): character cannot be converted to single byte

 GDB を使って、wxUniChar::ToHi8bit() にブレークポイントを置いて実行すると、下のようなスタックトレースが得られた。

#0  0x006a7160 in wxUniChar::ToHi8bit(unsigned int) ()
#1  0x006ab08d in wxURI::Unescape(wxString const&) ()
#2  0x0063f9c5 in wxFileSystem::URLToFileName(wxString const&) ()
#3  0x00c3e89b in wxWebViewIE::onActiveXEvent(wxActiveXEvent&) ()
#4  0x005cc440 in wxAppConsoleBase::CallEventHandler(wxEvtHandler*, wxEventFunctor&, wxEvent&) const ()

 wxURI::Unescape() で、日本語文字を含む文字列をデコードしようとして、引っかかっていた。そりゃそうだ、URI は本来7ビット文字で表現されるはずなのに、wxWebView がパーセントエンコードを受け付けないから日本語ファイル名を強引に渡しているわけだからな。

 実は、wxWidgets の Git 最新版を見ると、8ビット文字列を wxURI::Unescape() で受け付けるように修正されていた。下のコメントに、作者の無念がにじむ。

URIs can contain escaped 8-bit characters that have to be decoded using UTF-8 (see RFC 3986), however in our (probably broken...) case we can also end up with not escaped Unicode characters in the URI string which can't be decoded as UTF-8. So what we do here is to encode all Unicode characters as UTF-8 only to decode them back below. This is obviously inefficient but there doesn't seem to be anything else to do, other than not allowing to mix Unicode characters with escapes in the first place, but this seems to be done in a lot of places, unfortunately.

 いや、broken コードを書いている本人として言い訳させてもらうけど、Windows 版の wxWebViewIE がちゃんとパーセントエンコードされた URI を受け取ってくれれば、こんなことしなくて済むわけですよ。悪いのは MS(というか IE8)だ。IE8 なんか捨ててしまえ、とお思いか。でも、私が想定しているユーザーの中には、ふっるい PC を後生大事に使っている人だっているわけですよ。Windows 7 のサポートが切れてようがお構いなし。だから Windows 7 のサポートは切れない。上のコメントを書いて、あえて非道な URI をサポートした wxWidgets チームの人も、同じ考えだと思う。

 結局、3.1 の wxURI::Unescape() をバックポートして、対応することにした。wxWidgets をコンパイルし直さなくても、uri.cpp をプロジェクト内にコピーして、コンパイル・リンクすればよい。wxWidgets ライブラリ内のオブジェクトよりも自前の uri.cpp が優先されるから、問題なく置き換えできる。

 逆に、新しいブラウザを使っている人は大丈夫か、という問題もある。IE なしで Edge だけ、とかね。全般的に wxWidgets 3.1 系に乗り換えた方がいいかもしれない。でも、そうすると Mac OS 10.6 のサポートを切ることになるんだよな。こっちはもういいんじゃないか、という気もするんだけど。

タグ:Lua Mac wxWidgets
Posted at 2021年08月28日 15:27:57
email.png