VC2010でwxWidgetsを使う

wxWidgetsはクロスプラットフォームでGUIアプリを作れるライブラリだがここではVC2010を使って実験した。

wxWidgetsのページからダウンロード、ここではwxWidgets-3.0.0.7zをダウンロードした。作業フォルダはC:\work\wxWidgetsにしてここに展開した。

最初にライブラリを作らなければならない、ここではスタティックライブラリを作る。Visual C++ 2010 Expressで”C:\work\wxWidgets\build\msw\wx_vc10.sln”を開き、ソリューション構成を「Debug」にして、ソリューションのビルドを行う。これによりC:\work\wxWidgets\lib\vc_lib配下にライブラリとsetup.hが作られる。

つぎに新しくソリューションを作る。win32 windowsアプリでここでは名前はmywxappとした。

プロジェクトのプロパティで
追加のインクルードディレクトリにC:\work\wxWidgets\includeとC:\work\wxWidgets\include\msvcを追加
追加のライブラリディレクトリでC:\work\wxWidgets\lib\vc_libを追加
追加の依存ファイルで、wxbase30ud.libとwxmsw30ud_core.libを追加
リソースの追加のインクルードディレクトリにC:\work\wxWidgets\includeを追加

ソースコードはここを参考に以下のようにした。

実行結果
be21b3c5-f0aa-4d1e-8efd-4e0819feea0e

wxWidgetsはMFCと同じような構成でWinMainはライブラリが持ち、App,Frameなどがあり、メッセージを処理するマクロがある。特徴は他のプラットフォームでも動くことなのでやってみよう。

vc2005のspを調べる

レジストリのHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DevDiv\VC\Servicing\8.0\SPに記述されている。

自分の環境ではSP0のときのclのバージョン
C:\Program Files\Microsoft Visual Studio 8\VC>cl
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80×86
Copyright (C) Microsoft Corporation. All rights reserved.

SP1のとき
C:\Program Files\Microsoft Visual Studio 8\VC>cl
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80×86
Copyright (C) Microsoft Corporation. All rights reserved.

このバージョンはIDEのバージョン情報で表示されるもののようだ。

2008でも大体同じらしい。

Windows APIのSIDとACL

前回のSIDがAPIのCインタフェースでどうなっているのか。

Everyoneを表すSIDであるS-1-1-0、これはworldとも呼ばれるが、最初のS-1は固定、次の1がEveryoneを表すauthorityが以下のようにdefineされている。

以下のように定義する。

最後の0がEveryoneを表すRIDで以下のように定義されている。

ここから内部表現であるSIDへのポインタPSIDを得るにはAllocateAndInitializeSidを使う。

第1引数がauthority
第2引数がsubauthorityの数で最大8個まで指定でき、全部引数で渡す。RIDはsubauthorityの一つのようだ。
最後の引数が結果のSIDが返る。SIDを使い終わったらFreeSidで解放する。

ここからACLを作成するにはSetEntriesInAclを使う。ACLはACEのリストでACEの中にSIDがある。
この関数は以下のように宣言されている。

この関数はEXPLICIT_ACCESSという構造体を渡す。以下のように宣言されている。

grfAccessPermissionsはDWORDのビットマスクの変数で読み込みや書き込みなどを指定する。たとえば以下のような値を指定できる。

grfAccessModeは許可、拒否をなどを指定する。以下のenumを使う。

この2つがエクスプローラなどのファイルのセキュリティで表示されるものなのだろう。

grfInheritanceは継承関係を指定するがここではスルー、NO_INHERITANCE(=0)などを指定する。

TrusteeはTRUSTEE構造体、以下のように宣言されている。

pMultipleTrusteeはNULL固定
MultipleTrusteeOperationはNO_MULTIPLE_TRUSTEE固定
TrusteeFormは最後の引数の型を指定する。TRUSTEE_IS_SID(=0)を指定してSIDを渡す。
TrusteeTypeは渡すSIDがユーザかグループかを指定するらしいが、これはSIDで指定されるはずなので重複な気がする。everyoneの場合はTRUSTEE_IS_WELL_KNOWN_GROUPを指定する。
ptstrNameでSIDを指定する。

OldAclは既存のACLに追加する場合に指定する。新しく作る場合はNULL。
NewAclに結果が返る。使い終わったらLocalFreeで解放する。

これでACLができたので、これをたとえばファイルに適用するにはSetNamedSecurityInfoを使う。詳細はスルー

C:\T\Test.txtをeveryoneでの読み書き許可を与えるには以下のコードになる。

ファイルのセキュリティをエクスプローラで見るとeveryoneが追加されているはず、vista以降は管理者権限が必要かもしれない。このコードは新規のACLを指定したにもかかわらず、ファイルのセキュリティには他のACLも表示されるが、これは継承しているためだと思われる。

英語版のWindowsで日本語ソフトを実行する

WindowsソフトウェアにはUnicodeベースで作られたものとコードページベース(非ユニコード)で作られたものがある。Unicodeアプリはどの言語のWindowsでも文字化けせずに動くが(フォントがあれば)、コードページの方は文字列がshift-jisなどで記述されていて、それが日本語OSならshift-jisとして解釈するが、他の言語のOSだとそう解釈しないため文字化けが起こる。

直す方法はOS全体の設定を日本語にする方法とAppLocaleを使う方法がある。

OSの設定を変える方法

以下のように「地域の設定」からnon-Unicodeの設定をJapaneseに変える。
209589ab-7931-4b7a-9752-0568f23a8001

17d2226e-5e35-4b18-b327-2e48099a241d

AppLocale (古い:Windows XPくらいまでしか使えない)

AppLocaleを使えば、起動するアプリごとに言語を設定できる。Windows 7や8は非対応になっているがインストールするときに以下のようにCompatibility Modeに設定すればインストールできる。

9adc5a89-f88b-4d18-9241-2bee3c4fde67

AppLocaleの使い方は簡単で実行ファイルを指定すればいい。ショートカットも作ってくれる。

LocalEmulator

LocalEmulatorをインストールしてエクスプローラのコンテキストメニューのから日本語で起動できる。

WindowsのセキュリティオブジェクトとACLとトークン

Windowsでファイルが削除できない場合、他のプロセスが使っているか、セキュリティで拒否されているかだが後者の場合のことを調べると結構大変なことがわかる。

Windows 2000以降からセキュリティ機能が強化され、ファイルやプロセスやスレッドなどのカーネルオブジェクトはセキュリティディスクリプタ(SD)をもつ。SDにはACL(Access Control List)が定義される。ACLはACE(Access Control Entry)のリストでACEはSIDとパーミッションをもつ。SIDはユーザやグループの識別子で、表現方法も一様ではない。コードで使う場合は、SID構造体は定義されておらずvoid*で扱う、文字列で扱う表示法は2つあるようで1つは「S-1-」で始まる文字列、もう一つはSDDLで定義される文字列。Sで始まる文字列はレジストリなどに記述されたりしているのでこれを調べる。これはディレクトリ構造あるいは電話番号のように理解することができると思う。
最初のS-1-は今のところたぶん固定でその次の数字がidentifier-authorityになりその次がRID(relative identifier)になる。

定義済みのSIDがいくつかある

Universal well-known SID String value Identifies
Null SID S-1-0-0 A group with no members. This is often used when a SID value is not known.
World S-1-1-0 A group that includes all users.
Local S-1-2-0 Users who log on to terminals locally (physically) connected to the system.
Creator Owner ID S-1-3-0 A security identifier to be replaced by the security identifier of the user who created a new object. This SID is used in inheritable ACEs.
Creator Group ID S-1-3-1 A security identifier to be replaced by the primary-group SID of the user who created a new object. Use this SID in inheritable ACEs.

これをみるとSIDはLinuxのユーザ、グループよりも広い概念で、ある動作をしている人や、ある概念なども記述しているものであるようだ。

まとめると
S-1-[authority]-[RID]-
になる。authorityはコードではXX_AUTHORITYで#defineされており、RIDはXX_RIDで#defineされる。

authorityが
0 = SECURITY_NULL_SID_AUTHORITY
1 = SECURITY_WORLD_SID_AUTHORITY、すべての人、WindowsだとEveryoneが相当する。
2 = SECURITY_LOCAL_SID_AUTHORITY、ローカルで使ってる人
3 = SECURITY_CREATOR_SID_AUTHORITY、作った人
5 = SECURITY_NT_AUTHORITY、NTはWindows NTのことか?Windowsのユーザなどはこれが使われる。

RIDはautorityに依存する。
S-1-2-0はautorityが2、RIDが0で、ローカルの人を表すと思われる。
S-1-2-1はautorityが2、RIDが1で、ローカルでログオンしてる人を表すと思われる。

S-1-5-で始まるものはWindowsが管理しているものでいろいろあるが一般ユーザはS-1-5-21-で始まるようだ。

レジストリエディタでHKEY_USERS配下を見るといくつかのSIDがマウントされており自分と一致するのはHKEY_CURRENT_USERにマウントされている。

セキュリティオブジェクトにアクセスする方はtokenを使って行う。このtokenと対象オブジェクトのACEが次々比較されアクセスできるかが決まる。ACLが存在しない場合2つの意味があってACLそのものがない場合と、ACEが0個の場合がある、前者の場合はアクセスは許可され、後者の場合は拒否される、よってACEには基本的に許可を記述し、許可の中で例外的なものを拒否記述する。ACEは上から順に評価され、おそらくSID一致のエントリーが見つかったら更なる処理はしないので拒否は上に書かないとならない。ACLが存在しないとはFATのようなもののことを言っていてNTFSではそういうことはないのだと思う。

SIDの比較はtokenが持っているログインユーザのSIDや属しているグループSIDで行う。上記の話は読み書きでのことだがファイルを作成する場合はtokenが持っているデフォルトのSDが使われる。

長いのでまた今度書こう。最初に書いたファイルを削除したい場合はcygwinをインストールして

$ rm -rfv /cygdrive/C/Dirなどとやるのが早い。