表(?)の掲示板https://www.activebasic.com/forum/では、phpBBが使われています。そのphpBBを最新版3.2に更新しました。そのときやったことのまとめです。

phpBB 3.2ではスタイルprosilverが標準となっていますが、ここでは以前より使い続けているsubsilver2を引き続き使い続けています。以下の手順もsubsilver2に絞ったものとなっています。

  1. 公式サイトのphpBB • Download phpBB 3.2からダウンロード。
  2. subsilver2スタイルの導入。phpBB • subsilver2 – Contribution Detailsから最新の3.1.10をダウンロードする。
  3. GitHub – msr-i386/phpBB3_language_jaのClone or downloadのDownload ZIPのリンクから、ZIPファイルをダウンロードする。
  4. 上記3ファイルを同じディレクトリに解凍する。
  5. ディレクトリstyles/prosilverを削除する。
  6. enの内容を元にphpBB3/styles/subsilver2/theme/ja/stylesheet.cssを作る。
  7. ここまでの手順で用意したファイルを使い、あとは通常どおりphpBB公式ウェブサイトにあるUser GudeのUpgrading from 3.1 to 3.2の手順に従って処理する。

ファイルを解凍する以降の手順について、実際には以下のコマンドを実行しました。ZIPファイルに対応しているbsdtarを使っています。

tar xf phpBB-3.2.0.zip
tar xf subsilver2_3.1.10.zip -C phpBB3/styles
tar xf phpBB3_language_ja-msrmod.zip --strip-components 2 -C phpBB3 --include=phpBB3_language_ja-msrmod/root/language
tar xf japanese_1_0_5.zip --strip-components 4 -C phpBB3/styles/subsilver2/theme
rm -r phpBB3/styles/prosilver
cp phpBB3/styles/subsilver2/theme/en/stylesheet.css phpBB3/styles/subsilver2/theme/ja

なお、実際には、phpBB3/styles/subsilver2/theme/jaに日本語フォントに関するfont-familyの指定を追加しています。それについては、直接https://www.activebasic.com/forum/styles/subsilver2/theme/ja/stylesheet.cssを見てください。

これを書くにあたって、prosivlerのほうも同様の手順でできそうかどうか試してみました。結果、画像ファイルの配置がsubsilver2と同じかどうか自信が持てなかったのでやめました。

phpBB 3.2はPHP 7系(7.0, 7.1)対応を謳っています。そこで、phpBB 3.2に上げることに決めました。というわけで、www.activebasic.comおよびdev.activebasic.comのサーバーは現在PHP 7.1が動いています。

この記事のカテゴリ

  • ⇒ phpBB 3.2を日本語化して使う

私がWindows APIプログラミングを始めた頃から、MSDNライブラリのCreateWindow関数にはこんなことが書いてありました。従って、NT系ならここはNULLで良いのだと、最近まで信じていました。

hInstance
Windows 95/98:ウィンドウに関連付けられたモジュールのインスタンスハンドルを指定します。

Windows NT/2000:このパラメータは無視されます。


ところが、最近こんなのを見つけたんです: What is the HINSTANCE passed to CreateWindow and RegisterClass used for? – The Old New Thing

ウィンドウクラスはHINSTANCEとクラス名で識別されるのだということが書いてあります。あれあれ?この説明のとおりなら、HINSTANCE必要では?と思ったところ、コメント欄に決定打がありました。

Raymond Chen – MSFT says:
April 18, 2005 at 12:52 pm

CornedBee: That’s a doc bug; I’ve submitted a correction. All versions of Windows have always used the HINSTANCE to identify the class.

そして、最新情報に更新され続ける、英語のほうのMSDNライブラリを開けばこうです。

hInstance [in, optional]

Type: HINSTANCE

A handle to the instance of the module to be associated with the window.

いつの間にか書いてあることが変わっているではありませんか!

そんなわけで、CreateWindow関数(もちろんCreateWindowEx関数も)のHINSTANCEの実引数は昔も今もちゃんインスタンスハンドルを渡さないといけないということでした。

この記事のカテゴリ

  • ⇒ CreateWindow関数にはHINSTANCEが必要

手書きのリソーススクリプトなら先頭で、Visual C++プロジェクトでなら「読み取り専用ヘッダーファイル」で指定するヘッダーファイルの話の続きです。前回(リソース関係のヘッダーファイルまとめ)、いろんなリソーススクリプト用のヘッダーファイルを紹介しました。今回は、私の選択基準を書きます。

MFCを使用するWTLを使用するno<afxres.h>yesVC++ 2012以上を使用するno<atlres.h>yes<winres.h>yes<winresrc.h>no

  • アプリでMFCを使っているなら、MFCの<afxres.h>を使います。
  • アプリでWTLを使っているなら、WTLに入っている<atlres.h>を使います。
  • Visual C++ 2012およびそれ以降を使っているなら、<winres.h>を使います。
  • それ以外の場合、<winresrc.h>を使います。たとえば、Visual C++ 2010までだったり、MinGWなどだったりする場合です。

もっとも、これに従うと、ほとんどは<atlres>か<winres.h>という結論になります。私は新規で作るときにMFCを使うことはありませんし、最近のバージョンのVisual C++ばっかり使っているからです。

念のため追記しておきますが、これが絶対の基準であるとは思っていません。だから、「私の選択基準」という表現にしました。

この記事のカテゴリ

私が知る、リソーススクリプト用のヘッダーファイルのまとめです。

afxres.h
MFCのヘッダーファイルです。winres.hをインクルードしています。リソースID用の定数を多数定義しています。その中にはAFX_IDW_TOOLBARなどAFXで始まるものもあれば、ID_FILE_NEWのように汎用的に使えそうなものもあります。
atlres.h
WTLのヘッダーファイルです。Visual Studioの付属品ではありません。winresrc.hをインクルードしています。afxres.hのように、リソースID用の定数を多数定義しています。ATL/WTL用にATL_IDW_TOOLBARなどATLで始まるものもあります。そのほか、VS_VERSION_INFOやIDC_STATIC、ID_FILE_NEWなど、winres.hやafxres.hと同等のものも定義されています。
winres.h
前回の記事に書いたとおり、以前はMFC扱いでしたが、今はWindows SDKに収録されています。winresrc.hをインクルードしています。定数VS_VERSION_INFOと定数IDC_STATICの定義があります。
winresrc.h, windows.h
Windows SDKあるいはPlatform SDKに昔からあります。どちらをインクルードしても同じです。リソースコンパイル時のwindows.hは、winresrc.hをインクルードするようになっているためです。

以下、細々とした話です。

  • Visual Studioのリソースエディタでダイアログにスタティックコントロールを設置すると、リソースIDがIDC_STATICになります。そのため、Visual Studioでデスクトップアプリを作るなら、windows.hやwinresrc.hでは足りません。それ以外を使用するのが良いでしょう。
  • 最近のVisual Studioでは、デフォルトのオプションだとMFCが入りません(C++自体もそうですけど)。MFCが入っていないということはafxres.hもありません。アプリ自体でMFCを使っていない場合、afxres.h以外を使うのがおすすめです。
  • winres.hはWindows SDKにはありますが、現在のところMinGW-w64にはないようです: /mingw-w64-headers (Tag v5.0.1)。

このラインナップ、私が認識しているものを並べたものです。なので、Visual StudioやWindows SDKに入っていないatlres.hを含めています。

この記事のカテゴリ

リソース関係のヘッダーファイルwinres.hの話です。これはMFCのヘッダーファイルだったはずですが、少し前からWindows SDKに収録されるようになりました。

(さらに…)

この記事のカテゴリ

以下のコードのように、実際には何も行わず、ただミューテックスの要件を満たすだけの実装は簡単に作れるでしょう。Null Objectパターンの一種と言えますよね。

class null_mutex
{
  void lock() {}
  void try_lock() {}
  void unlock() {}
};

Boostには、そんなクラスがなんだかあちこちにあるようです。

Boost.Threadのものが最も汎用的です。BoostのUpgradeLockableコンセプトまで実装しています。それに次ぐのがBoost.Interprocessのものです。残りはLockableコンセプト(lock, try_lock, unlock)のみ実装のようです。

私自身は、boost::signals2::dummy_mutexなら使ったことがあります。シングルスレッドでboost::signals2::signalを使うという状況でした。

この記事のカテゴリ

  • ⇒ Boostのなんにもしないミューテ(ッ)クス

Visual C++ 2015および2017 RCでは、<codecvt>の各クラステンプレートにchar16_tやchar32_tを組み合わせるとリンクエラーになるという問題があります。今回、これに対する条件付きのWorkaroundについて書きます。

まずは、エラーになるコードの例を提示します。

#include <codecvt>
#include <string>
#include <cassert>
#include <locale>
 
int main()
{
  std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter_utf32;
  std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter_utf16;
 
  std::string u8str = u8"\U0001F359";
 
  std::u32string u32str = converter_utf32.from_bytes(u8str);
  std::u16string u16str = converter_utf16.from_bytes(u8str);
}

これをVisual C++ 2015でコンパイル・リンクするとこんなエラーメッセージが出てきます。

u.obj : error LNK2019: 未解決の外部シンボル "public: static class std::locale::id std::codecvt::id" (?id@?$codecvt@_SDU_Mbstatet@@@std@@2V0locale@2@A) が関数 "public: __thiscall std::locale::locale >(class std::locale const &,class std::codecvt_utf8_utf16 const *)" (??$?0V?$codecvt_utf8_utf16@_S$0BAPPPP@$0A@@std@@@locale@std@@QAE@ABV01@PBV?$codecvt_utf8_utf16@_S$0BAPPPP@$0A@@1@@Z) で参照されました。
u.obj : error LNK2019: 未解決の外部シンボル "public: static class std::locale::id std::codecvt::id" (?id@?$codecvt@_UDU_Mbstatet@@@std@@2V0locale@2@A) が関数 "public: __thiscall std::locale::locale >(class std::locale const &,class std::codecvt_utf8 const *)" (??$?0V?$codecvt_utf8@_U$0BAPPPP@$0A@@std@@@locale@std@@QAE@ABV01@PBV?$codecvt_utf8@_U$0BAPPPP@$0A@@1@@Z) で参照されました。
u.exe : fatal error LNK1120: 2 件の未解決の外部参照

さて、エラーメッセージを読むと、1件目はstd::locale::id型のstaticメンバー変数std::codecvt<char16_t,char,struct _Mbstatet>::idが見つからないという内容です。2件目も同じ内容でchar32_tになっているだけです。ということは、これを自分で定義したら良いのではないでしょうか?

というわけで、こんなコードを書いたらうまくいきました。コンパイル・リンクできてちゃんと実行できました。

#include <codecvt>
#include <string>
#include <cassert>
#include <locale>
 
// この2行を追加
std::locale::id std::codecvt<char32_t, char, std::mbstate_t>::id;
std::locale::id std::codecvt<char16_t, char, std::mbstate_t>::id;
 
int main()
{
  std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter_utf32;
  std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter_utf16;
 
  std::string u8str = u8"\U0001F359";
 
  std::u32string u32str = converter_utf32.from_bytes(u8str);
  std::u16string u16str = converter_utf16.from_bytes(u8str);
}

ただし、この方法を使うには条件があります。それは、VC++ランタイムを静的リンクする場合(/MT/MTdコンパイルオプション)だけ使えるというものです。/MD/MDdだと、問題となるstaticメンバー変数idが__declspec(dllimport)付きの宣言となってしまうため、この方法が使えません。別のリンクエラーになります。

ところで、以下のcpprefjpの各ページのサンプルコードもこの問題に該当します。それぞれのサンプルコードの作成・動作確認にあたり、私はこの方法で乗り切りました。

まとめです。

  • codecvt_utf16, codecvt_utf8, codecvt_utf8_utf16のいずれかに、char16_tかchar32_tを使うとリンクエラーが出る。
  • そうなったら、codecvtクラステンプレートののstaticメンバー変数idを自分で定義すれば、リンクが通る。

バグ報告は出ているそう(Visual C++における文字コード変換 – C++と色々)なので、将来的にはVisual C++が直ることを期待します。あと/MD, /MDdで使えるWorkaround欲しいです。

この記事のカテゴリ

  • ⇒ VC++ 2015のcodecvtでリンクエラーになる問題の回避策

Visual C++ 2015と2017 RCで、以下のプログラムが期待どおりに動きませんでした。

#include <iostream>
#include <sstream>
#include <iomanip>
#include <ctime>
 
int main()
{
  std::istringstream s("20170110");
 
  std::tm x = {};
  s >> std::get_time(&x, "%Y%m%d");
 
  char buf[255];
  strftime(buf, sizeof(buf), "%Y-%m-%d", &x);
  std::cout << buf << std::endl;
}

%Yで2017だけパースされることを期待しているのですが、Visual C++の実装では、20170110まで読み込んでしまうようになっていました。

libstdc++やlibc++では、ちゃんと2017だけ読み込む実装だったので、Visual C++のほうに問題がありそうです。

2017年1月15日追記: 同じ問題が報告されているのを見つけました。std::get_time fails when using formats without separators – Developer Community

この記事のカテゴリ

  • ⇒ VC++でstd::get_timeがなんかダメ
  • ⇒ VC++でstd::get_timeがなんかダメ

主にLinuxで使われるGNU C Library (glibc)では、wchar_tをUCS-4 (UTF-32)固定としている、そう私は認識しています。しかし、ずっとその根拠を確かめずにそう思い込んでいる状態だったので、気になって調べました。

マニュアルにそのような記載が無いかと探した結果、The GNU C Library: Selecting the Conversionに以下の記述を見つけました。

The wide character set is always UCS-4 in the GNU C Library.

このほか、LinuxのMan page of UNICODEには、以下の記述があります。

GNU/Linux では、C 言語の型 wchar_t は符号付き 32 ビット整数型である。 その値は C ライブラリにより (すべてのロケールにおいて) 常に UCS コードの値として解釈される。 これを GNU C ライブラリがアプリケーションに知らせるための規約として、 定数 __STDC_ISO_10646__ を定義する。 これは ISO C99 規格で指定されている。

なお、__STDC_ISO_10646__を定義している箇所も見つけました。Move __STDC_* predefined macros from features.h to stdc-predef.h. · git-mirror/glibc@ff3b3d8 · GitHubです。

というわけで、glibcにおいてwchar_tは常にUCS-4である、という認識で良さそうです。

この記事のカテゴリ

  • ⇒ glibcのwchar_tがUCS-4であることを確認した
  • ⇒ glibcのwchar_tがUCS-4であることを確認した

次の表を見てください。<time.h>あるいは<ctime>でtime_tとtm構造体との変換を行う関数をまとめました。

time_t→tm構造体 tm構造体→time_t
現地時刻 localtime mktime
UTC gmtime

表の「?」の部分、UTCでtm構造体からtime_tに変換する関数、それがCおよびC++の標準ライブラリにはありません。

仕方ないので、非標準でもいいから何かないかと探しました。どうやら、Unix系の一部にはtimegm、Visual C++には_mkgmtimeという関数があることが分かりました。

Linux glibc, BSD系列, Cygwinなど
timegm関数 (Linux, FreeBSD)
Visual C++
_mkgmtime

このほか、Linuxのmanには、Unix系一般に通用しそうな方法が説明されています。setenvで環境変数TZを設定のうえ、mktimeを呼び出すというやり方です。

なおこれ、std::chrono::system_clock::time_point ←→ std::time_t ←→ std::tm ←→ (std::put_time, std::get_time)というstd::chrono::system_clock::time_pointからの入出力の過程で必要になったので、調べました。

この記事のカテゴリ

  • ⇒ tmからtime_tにUTCで変換する関数を探した
  • ⇒ tmからtime_tにUTCで変換する関数を探した

次ページへ »