たぶん、見て価値があるのは2006年以降。2004年と2005年は試行錯誤した様子を日記として書いていたので、無駄な情報も多いです。
自分用の備忘録なので、細かい説明は書いていません。あしからず。
09.10.13に書いた方法は、ページを去る直前に機能が発動してしまうので、動画ページ以外へ離脱しようとするときもプレイリストに戻されてしまう。
仕方が無いのであまりキレイではないけれど代替策を講じた。具体的には、動画ページをロードする時、次に再生すべき動画ページを取得するとともに、前回保存された再生すべき動画ページと現在の動画ページを比較して違っていたら本来再生すべき動画ページへ飛ばすのだが、ただし現在のページが動画ページ以外だったら何もしない、というちょっとトリッキーなアルゴリズム。
自動ジャンプページの場合、ほぼ確実にそちらへ飛んでから、上記の機能が発動するため、見てもいない動画が一瞬再生されたこととして履歴に残ってしまうのが難点。気持ち悪いといえば気持ち悪いのだけれど仕方が無い。unload時、次に表示されるページを取得できればよかったのだけれど、それはセキュリティ上の問題で出来ないらしい。
それででは解説。
335行目付近にある playNext 関数の、以下のように「//???」となっている行をコメントアウトするとともに、直後の347行目付近へ「//???>>>>>>」から「//???<<<<<<」で囲まれたコードを追加する。
playNext: function () {
//???var video;
//???if (this.random)
//??? video = this.playlist.popRandom();
//???else
//??? video = this.playlist.pop();
if (video) {
if (this.loop) this.playlist.push(video);
this.playlist.save();
video.play();
}
},
//???>>>>>>
reserveNext: function() {
video = null;
if (this.random)
video = this.playlist.popRandom();
else
video = this.playlist.pop();
return video;
},
video: null,
//???<<<<<<
それから、ソースの最後付近に以下の「//???>>>>>>」から「//???<<<<<<」で囲まれたコードを追加する。
//???>>>>>>
window.addEventListener("load", __NicoNicoPlaylistLoad, false);
function __NicoNicoPlaylistLoad(){
var shouldBePlayedUri = GM_getValue("shouldBePlayedUri", "");
if(window.location.href.indexOf("http://www.nicovideo.jp/watch/") == 0 && window.location.href != shouldBePlayedUri && shouldBePlayedUri != "" ){
window.location.href = shouldBePlayedUri;
}else{
var reservedUri = controller.reserveNext().getPlayUri();
if(window.location.href.indexOf("http://www.nicovideo.jp/watch/") == 0){
GM_setValue("shouldBePlayedUri", reservedUri);
}else{
GM_setValue("shouldBePlayedUri", "");
}
}
}
//???<<<<<<
})();
【Firefox について】バージョン=3.5.7/ダウンロードページ=http://mozilla.jp/firefox/
【NicoNicoPlaylist について】バージョン=1.13/ダウンロードページ=http://d.hatena.ne.jp/kotas/20091219/playlist
【Greasemonkey について】バージョン=0.8.20091209.4/ダウンロードページ=
※上記情報はいずれも 2010.01.19 現在。
Visual Studio 2008 の C++/CLI でプログラムを作る場合、プロジェクトのプロパティで「共通言語ランタイムのサポート」を「安全な MSIL 共通言語ランタイム サポート (/clr:safe)」にしないと、プログラム全体で 2GB までしかメモリを使用できない。
Greasmonkey は Firefox のアドオンで、任意のページに自分で書いた Javascript を埋め込んで実行させることができるという便利ツール。
それで最近「ニコニコ動画でプレイリストが使える Greasemonkey スクリプト(NicoNicoPlaylist)」というものを使ってニコニコ動画を再生している。
ところが、動画中にニコスクリプトで自動ジャンプが設定されていると、NicoNicoPlaylist でジャンプする前に次の動画へ飛ばされてしまう。これは都合が悪い。
この対策として、NicoNicoPlaylist のコードを以下のように改変して使わせてもらっている。
//712行目付近 元コード
})(function () {
var t = setInterval(function() {
if (player.getStatus() == "end") {
clearInterval(t);
controller.playNext();
}
}, 1000);
});
}
//
// Style definitions
//
//712行目付近 改変コード
})(function () {
var t = setInterval(function() {
if (player.getStatus() == "end") {
//???ニコスクリプトによるジャンプ対策
__unloadedByNicoNicoPlaylist = true;
clearInterval(t);
controller.playNext();
}
}, 1000);
});
}
//???ニコスクリプトによるジャンプ対策
window.addEventListener("unload", __NicoNicoPlaylistUnload, false);
var __unloadedByNicoNicoPlaylist = false;
function __NicoNicoPlaylistUnload(){
if(!__unloadedByNicoNicoPlaylist){
controller.playNext();
}
}
//
// Style definitions
//
原理は単純。unload イベントハンドラ内で、フラグを使ってこのイベントが NicoNicoPlaylist によるページ遷移で発生したのかそうでないのかを判定し、そうでない場合は本来行われるべき NicoNicoPlaylist のメソッドを実行している。ただし、上記の改変はあんまり細かくチェックしていない。今のところうまく動いているけれども、これは自分用のメモなのでもしまねされる方がいれば自己責任で。
【Firefox について】バージョン=3.5.3/ダウンロードページ=http://mozilla.jp/firefox/
【NicoNicoPlaylist について】バージョン=1.12/ダウンロードページ=http://d.hatena.ne.jp/kotas/20080725/playlist
【Greasemonkey について】バージョン=0.8.20090920.2/ダウンロードページ=
※NicoNicoPlaylist のバージョンは、ダウンロードページには 1.10 と書いてあるんだけど、実際にダウンロードしてみると 1.12 になっている。
※上記情報はいずれも 2009.10.13 現在。
Visual Studio (2008 で確認) の C++ でフォームを作成すると、クラス宣言の冒頭に以下のような注意書きが書かれている。
/// TestForm の概要 /// /// 警告: このクラスの名前を変更する場合、このクラスが依存するすべての .resx ファイルに関連付けられた /// マネージ リソース コンパイラ ツールに対して 'Resource File Name' プロパティを /// 変更する必要があります。この変更を行わないと、 /// デザイナと、このフォームに関連付けられたローカライズ済みリソースとが、 /// 正しく相互に利用できなくなります。
これは名前空間でも言えることらしい。特に、名前空間を深くするときは注意が必要だ。クラス名の変更だけなら全置換で済むけれど、名前空間を深くした場合には namespace 宣言を修正したり、usingnamespace を修正したり、「::」演算子を使うように修正したりしなければいけないので、一筋縄にはいかない。そしてもっとも注意すべきが .resx の「プロパティ ページ」を開いて「マネージ リソース」という項目の「リソース ファイル名」を修正しなければいけない点だ(この項目値に合わせて .resources ファイルが作成され、最終的にアセンブリ本体へ埋め込まれる)。クラス名の全置換ならプロジェクトを管理するファイルも含めて全部修正できるからよいのだが、全置換が出来ない以上、こういった細かな修正も手動で行わなければならない。
ちなみに、名前空間やクラス名の変更が .resx に反映されていないとリソース(アイコンなど)読み込み時に以下のような例外が出る。
MissingManifestResourceException 指定されたカルチャまたはニュートラル カルチャに対して適切なリソースが見つかりませんでした。"Parof.Test.TestForm.resources" が適切に埋め込まれたか、実行時にアセンブリ "Test" にリンクされたか、または必要なサテライト アセンブリが読み込まれて完全に署名されていることを確認してください。
これは、名前空間「Test」の下に「TestForm」を作成した後、名前空間「Test」を名前空間「Parof」に入れて(コード的には入れ子でくくった)「Parof::Test」としたときにスローされた例外である。
Visual Studio が生成する .resx を使わない場合、自分で適当な .resx リソースファイルを追加してその中にリソースを埋め込んでおいて、以下のようにフォームのコンストラクタ等で呼び出す方法もある。
Assembly^ assembly = System::Reflection::Assembly::GetAssembly(TestForm::typeid);
ResourceManager^ rm = gcnew System::Resources::ResourceManager("Test.Test", assembly);
this->Icon = (cli::safe_cast<System::Drawing::Icon^ >(rm->GetObject(L"TestIcon")));
これは「Test.resx」に「TestIcon」を埋め込んでおいて、「Parof::Test::TestForm」のコンストラクタでこれを読み込んでいる例である。「ResourceManager」のコンストラクタの引数は作成した .resx の「リソース ファイル名」と合わせればよい(.resources は書かなくてよい)。
なお、.resx のプロパティとは別に、プロジェクトの「プロパティ ページ」にも、「構成プロパティ」に「マネージ リソース」がある。ここの「リソース ファイル名」との兼ね合いで、リソースファイル(.resources)が正しく作成されないことがあるようなので注意。
ちなみに!フォームエディタでフォーム上に直接は位置されるのではないコンポーネント(ContextMenu、NotifyIcon、Timer など)も勝手に .resx の「その他」に登録されちゃったりしているので、名前空間やクラス名を変更すると思わぬバグを生む原因になりかねない。結局のところ、おとなしく Visual Studio の作法に従うのが正解か・・・。全ての名前空間やクラスを Parof 名前空間に置いている私としては不服で仕方がないのだが・・・。
そして上記の記述は試行錯誤しながら行ったために正しさが保証できないので、うまくいかなければ .resx を作り直したり、いろいろなプロパティを変更したり、ソリューションをクリーンしたりいろいろ試すしかない。
「warning C4566: ユニバーサル文字名 'char' によって表示されている文字は、現在のコード ページ ('ページ') で表示できません」
って警告が出たら、文字列の先頭に「L」を付けてみると良い。「L"横浜"」みたいに。
本来、UNICODE 環境では文字列の頭に「L」を付けるのが正しい作法らしく、つい忘れるとどこかの文字操作処理で思わぬトラブルに・・・
実際、Visual C++ で UNICODE な環境においてフォームやコントロールの生成を行うと、自動生成されたコードではテキストの頭にはちゃんと「L」が付いている。
必要に迫られて Java を使わなければいけない。とりあえず基本的なところのメモ。
基本的に1ソースファイルにつき1クラスとし、ファイル名とクラス名は一致させる。そうでないと文句を言われる。1ソース内にファイル名とは異なる2つ目以降のクラスを追加するのは大丈夫らしい。ただし、これは eclipse の場合(他はわからない)。
クラス名は大文字から始めることが推奨されている。
すべてのクラスはパッケージに属していないといけない。属するパッケージの指定はソースファイルの先頭で「package」文を使う。そのソースファイルのクラスはみんなそのパッケージに含まれる。ただし、package が未定義の場合、デフォルトパッケージ(default package)と呼ばれる特殊なパッケージに含まれるらしい。
パッケージ名とソースファイルの存在するフォルダの名前は一致していないといけない。
パッケージ名は小文字から始めることが推奨されている。
eclipse でソースファイルを追加するときはパッケージを選択して右クリック、「New」から「Class」でクラスを追加するようにしなければいけない。間違って「New」から「File」でテキストファイルを追加してしまうと、プロジェクトがクラスを認識してくれない。
私の愛用しているオーディオプレイヤーソフト jetAudio は、プレイリストに Wave ファイルを登録して連続で再生していくと、どういう訳か「ザーーー」という、テレビで言うところの砂嵐みたいなホワイトノイズとして再生されてしまう。
どの曲だと、とか、どういうタイミングで、とかいうことはなく、10曲ぐらい聞いていると1度は起こる現象だ。
多分、jetAudio の内蔵コーデックに問題があるのだろう。
この問題を解決するには、「Preferences」を開いて「Advanced」の「Input」にある「WAV File」のチェックをはずしれやればよい。多分これで Wave に関しては内蔵ではなく Windows 標準のものが使用されるので、問題は解決される。
タスクバーを見ると、常時15個ぐらいウィンドウが開いていて、もう24インチディスプレイ2枚じゃ足りない・・・、ので仮想デスクトップソフトを試行錯誤。最初は「Vista/XP Virtual Desktops」が良いかな(セカンドディスプレイだけ使うとか設定できる!)と思っていたんですが、微妙に動作が重かったり、不完全だったりするので「VirtuaWin」なるものに乗り換えた。こっちの方が安定して軽い気がするのでしばらくはこれで。
で、本題。私が利用している「v4.0」以降、右クリックメニューから「Window Rules」という機能の設定ができるようになったらしいのだけれど、ネットを見ても「よくわからない」という人が多いので説明する。
まぁ、Win32 API でプログラミングしてる人じゃなきゃ「Class name」とか書かれてもわからないよな・・・。
「Window Rules」は一言で言ってしまえば「こういうウィンドウはこういうルールに従ってね」っていう設定ができる。例えば、Firefox は必ず2枚目で起動してね、とか。
この「こういうウィンドウ」というウィンドウ指定をするのが「Class name」「Window name」「Process name」になる。ちなみに、全てを埋める必要はない。また「*」記号によるワイルドカード指定が可能(もちろん使わなくてもOK)。
それで「Class name」っていうのは、簡単に言ってしまえば「どんなタイプのウィンドウか?」を指定するんだけど、このタイプの名前は開発者が自由勝手に付けることができる(Windows で共通のパーツは同じだけど)。例えば、今私が使っている Firefox は「MozillaUIWindowClass」だ。しかしやっかいなのは、何か専用のツールを拾ってこない限り見る方法がないことである。私の場合、統合開発環境である Visual Studio に付いていたツールで見ることができた。
じゃぁ、普通の人はどうすればよいの?ということなんだけど、今度は VirtuaWin の Setup 画面を開いて Modules タブから WinList の Configure を開いてみよう。私もリストの詳細な見方はわからないのだけれども、とにかく「Class」という部分に Class 名が、「Title」という部分にウィンドウのタイトルバーに表示されるべきタイトルがリストアップされる。「Tile」から目的のウィンドウを探し出して、その Class 名を見つければ OK だ。
続いて「Window name」なんだけど、これは試していないけれどもヘルプを見る限り、上述したウィンドウタイトルのことだと思われる。
最後の「Process name」は、だまされてはいけない。タスクマネージャの「プロセス」に現れる「イメージ名」を書けばよいのかなと思いきや、ヘルプを見ると「フルパスで書け」とある。おかげで30分迷った。
まぁ、後の設定は適当な翻訳サイトで翻訳してもだいたいわかると思うが、冒頭で述べた Firefox は常に2枚目で開くという設定にしたいなら次のようにしよう。
・「Class name」は空、「Window name」は空、「Process name」は Firefox.exe のフルパスを書く。私の場合は「C:\Program Files (x86)\Mozilla Firefox\firefox.exe」となる。
・「Window rule enabled(ルールを有効化)」をチェック。
・続くラジオボタンは「Always manage windows of this type(この種類のウィンドウはいつも VirtuaWin が管理するよ)」を選択。
・「Automatically move windows of this type to Desktop:(自動的にウィンドウを指定のデスクトップへ移動するよ)」をチェックして隣の数字を移動したいディスプレイ番号(今回は「2」)に設定。
・「Move windows immediately((プログラムが起動したら)すぐにウィンドウを移動するよ)」をチェック(これをチェックしない場合は右クリックメニューから「Re-apply Rules」を実行したときに移動する)。
これで Firefox は常に2枚目で開くようになる(ハズ)。あと、ルールを新しく作ったり変更した時には「Add」や「Modify」ボタンをすのを忘れずに。
VirtuaWin を使っていて気づいたのは、ときどき VirtuaWin で管理できないウィンドウがあること。話は簡単で、VirtuaWin が一般権限で動作していて対象のウィンドウが管理者権限で開いていると管理できない。VirtuaWin も管理者権限で動かしてやろう。
だけど、スタートアップに入れている人は困ったことが起きる。管理者権限付きでスタートアップから起動しようとしてもブロックされてしまうのだ。そういう場合はタスクスケジューラを使えばよい。詳しくは拙作 KBMouse のヘルプに同種の問題が記載されているので、そちらをご覧いただきたい。
ListView のアイテム集合から、チェックされているアイテムを抜き出すには、CheckedItems や CheckedIndices を使うよりも、各アイテムの Checked プロパティを調べた方が圧倒的に早い。例えば
List^ ret = gcnew List (); for(int i = 0; i < this->listView->CheckedItems->Count; i++){ ret->Add(this->listView->CheckedItems[i]->Tag); } --------------------------------------------------------------------------------------------------- List ^ ret = gcnew List (); for(int i = 0; i < this->listView->Items->Count; i++){ if(this->listView->Items[i]->Checked) ret->Add((String^)this->listView->Items[i]->Tag); }
例えば仮想ディスク「D:\TargetVirtualDisk.vmdk」の容量を100GBに増やしたいなら、「VMWare Workstation」がインストールしてあるフォルダの「vmware-vdiskmanager.exe を以下のように実行すればよい。
vmware-vdiskmanager.exe -x 100GB D:\TargetVirtualDisk.vmdk
javascript において onclick されたエレメントを、そのハンドラ内で removeChild や replaceChild により取り除くと onclick のチェインが断ち切られ、たとえば document.onclick が実行されなくなるなどの弊害が起こるので注意が必要。
マザーボード上のオーディオピンは接続に難儀する。マザーの説明書とケース側のピンの表記が異なっているケースも多いためだ。そこで、いろいろな表記をまとめてみた.。
上段:Intel High Definition Audio(Azalia)、中段:AC97、下段:その他の表記例
| Port1L | ○ | ○ | GND |
| Mic-In | GND | ||
| MIC2 MIC2_L AUD_MIC- |
AGND GROUND AUD_VCC |
||
| Port1R | ○ | ○ | PRESENSE |
| Mic-Pow | PRESENSE | ||
| MIC2_R AUD_MIC+ |
+5VA AUD_VCC |
||
| Port2R | ○ | ○ | Sense1_Return |
| FrontR | FrontR-Ret | ||
| R-OUT HP_R Line_out_R AUD_FRONT_R |
R-RET MIC2_JD BLINE_OUT_R AUD_RET_R |
||
| Sense_Send | ○ | ||
| --- | |||
| Jack_Sense NC |
KEY | ||
| Port2L | ○ | ○ | Sense2_Return |
| FrontL | FrontL-Ret | ||
| L-OUT HP_L Line_out_L AUD_FRONT_L |
L-RET HP_HD BLINE_OUT_L AUD_RET_L |
VPNしていると、ネット接続すらもそちらへルーティングしていることに気づいた。問題解決はいたって簡単。クライアント側でセットアップされたVPNのプロパティを開いて、「インターネット プロトコル バージョン4 (TCP/IPv4)のプロパティ」の「全般」で「詳細設定」ボタンを押し、「TCP/IP 詳細設定」ウィンドウが開いたら「IP 設定」タブにある「リモート ネットワークでデフォルト デートウェイを使う」のチェックを外せばよい(「自動メトリック」はそのままでOK)。
Vista のファイル共有はファイアウォールと強く結びついている。「ネットワークと共有センター」の「ネットワーク探索」や「ファイル共有」、「プリンタ共有」を「有効」にしようとすると、ファイアウォールにある事前定義されたルール(ファイルとプリンタの共有)を有効にしようとする。もし、これらのルールが存在しないとこれらの機能は有効にならない。ただし、共有したいフォルダやプリンタについては、いったん共有してしまえば、その後は共有に必要なポートさえ開いておけば事前定義ルールの存否は影響しない。
マネージ型のオブジェクト(というよりは変数)は原則としてグローバルやアンマネージクラスに含めることはできない。
しかし、GCHandle クラスの Alloc メソッドを、引数 GCHandleType::Pinned として実行すると、対象のマネージオブジェクトが固定化されてアドレスを取得できるようになる (*1) 。
Alloc で取得した GCHandle は、さらに GCHandle クラスの ToIntPtr メソッドで、オブジェクトのアドレスを保持する IntPtr を取得し、取得された IntPtr の ToInt32 または ToInt64 メソッドを実行することで実際のアドレスを整数型で得ることができる。
逆に元のオブジェクトを得るには、IntPtr のコンストラクタに整数表現のアドレスを渡して IntPtr を構築し、それを GCHandle の FromIntPtr メソッドへ渡して GCHandle を取得、そのなかの Target プロパティを取得すればよい。
また、値型や配列をネイティブに扱いたい場合は、pin_ptr でネイティブなポインタのように扱うことができ、対象のオブジェクトは、アドレスが固定化される。例えば、array<int>^ ary に対して、pin_ptr<int> p = &ary[0] とすれば、この p は int* として扱える。
pin_ptr によるアドレス固定の効力は、その pin_ptr が他のオブジェクトを指すか、スコープから外れるまでとなる。しかし、GCHandle の Alloc でアドレスが固定化されていれば、pin_ptr が効力を失ってもアドレスが固定化されたままとなるので、通常の(int* のような)ポインタで指し続けることができる(と思う)。
ちなみに、コンパイルオプションがただの /clr や /pure であれば gcroot を使用する方法もある(説明省略)が、/clr:safe オプションを使用した場合は gcroot が使えない。
gcnew を使ってガベージコレクト付きでオブジェクトやメモリを確保した場合、delete しなくても使い終わった分は勝手に解放・回収してくれる。しかし、メモリの効率的な使用のために明示的な解放を行いたい場合もある。
そのようなときは delete するのではなく、変数に nullptr を代入して適当なタイミング(最後にまとめて等)で GC::Collect を呼ぶとよい。nullptr を代入することで明示的に「他から参照されていない」ことを宣言し、GC::Collect によって強制的にガベージコレクトするのである。もちろん、nullptr を代入しても、実際のオブジェクトが他から参照されていればガベージコレクトの対象からは外れる。また、GC::Collect の多用はパフォーマンスに影響するので、計画的に使用したほうがよい。
メニューから「ツール」を選び「オプション」を開く。「Windows フォームデザイナ」項目の「全般」を選び、「ShowGrid」を「True」にする。設定後、フォームは一度閉じて開きなおさなければならない点に注意。
「構成ファイル Visual Studio」「app.config」等のキーワードで検索するとよい。簡単に結論を書くと、実行ファイルと同じ場所に「実行ファイル名.exe.config」という設定ファイルを用意すればよい。普通、プロジェクトに「構成ファイル」を追加すると「app.config」というファイルが作成され、コンパイルすると実行ファイルのある場所に「「実行ファイル名.exe.config」の名前でコピーされる。ただし、なぜか C++ ではコピーされないので要注意。
ちなみに、特定のバージョンの Framework で動かす app.config のサンプルは以下の通り
<configuration> <startup> <!--supportedRuntime 上に記述されているランタイムが優先的に使用される。--> <supportedRuntime version="v3.0"/> <supportedRuntime version="v2.0.50727"/> </startup> </configuration>
Form のプロパティで「TopMost」を「True」にすれば最前面に表示されるが、これだけでは「デスクトップを表示」コマンドなどで非表示になってしまう。これを回避するには Form のプロパティで「ShowInTaskbar」を「False」にすればよい。ただし、その Form のタスクバーには表示されなくなる点に注意。
ListView で、コントロールがフォーカスを失っても選択されたアイテムが灰色で強調表示されるようにするには、HideSelection プロパティを「false」に設定する。
[プロジェクト] メニューの [プロパティ] を選択、[プロジェクト名 プロパティ ページ] ダイアログ ボックスの、[リンカ] フォルダの [詳細] カテゴリで、[エントリ ポイント] を main 等、適切なプロジェクトのエントリポイント関数に設定する。
FolderBrowserDialog や OpenFileDialog 等は内部で OEL を使用しているらしい。これらを使う場合は、スレッドのモードを「Single Thread Apartment (STA)」に設定しなければいけない。この設定を行うためには main 関数に STAThreadAttribute を設定すればよい。
[STAThreadAttribute]
int main()
{
...
}
コレがないと、例えば FolderBrowseDialog ではツリー部分が表示されなかったり、OpenFileDialog ではデバッグ実行時にエラーがでる。
Windows フォーム で ComboBox を編集不可能にするには、DropDownStyle を DropDownList にすればよい。
VS で作成されたドキュメントは XML 形式になっている。これを DCM 形式等に変換するには NDoc を利用する。NDoc は C# のためのツールと思われがちだが、C++/CLI で作成されたコードであれば、問題なく利用できる。
ただし、NDoc1.3.1 は .net framework 2.0 に対応していないので、
[NDocRoot]/bin
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<!--supportedRuntime 上に記述されているランタイムが優先的に使用される。-->
<supportedRuntime version="v2.0.50727" />
<supportedRuntime version="v1.1.4322" />
<requiredRuntime version="v1.1.4322" />
</startup>
</configuration>
プロジェクトのプロパティを開き、ツリーを「構成プロパティ」→「C/C++」→「出力ファイル」とたどり、「XML ドキュメントファイルの生成」オプションを「はい」にする。
コメントの書き方は、MSDN ライブラリの「キーワード」で「XML ドキュメント」を引く。「このセクションの内容」にある「ドキュメント コメントとして推奨されるタグ」を見れば大体わかるはず。
VS2005 ではプロジェクトをビルドしてエラーがあった場合「エラー一覧」タブを選択することによってエラーの一覧を表示させることができる。
ビルド完了時に、この「エラー一覧」タブを自動的に表示させるには「メニュー」から「オプション」を開き、左側のツリーから「プロジェクト及びソリューション」→「全般」とたどり、設定項目の「ビルド完了時にエラー一覧を表示」をチェックすればよい。
普通、コピーコンストラクタを作るには「&」を使うが、C++/CLI でコピーコンストラクタを作るには追跡参照「%」を使うようだ。
プロジェクトのプロパティで「構成プロパティ」「リンカ」「システム」とたどり、「サブシステム」を Windows にする。
C++/CLI では通常のポインタのかわりに「^」を使うが、これだと参照先の内容を変更できない(引数で int ^p とし、*p=10 とかはエラー)。この場合、追跡参照「%」をつかう。これは C++ でいうところの「&」みたいなもので、引数で int %p とすれば p=10 として変更が可能だ。マネージクラスならば Int32 ^%p として p = gcnew Int32(10) のようにすればよい。
mono で CGI が動かなかったのは、mono が使用するテンポラリディレクトリへアクセスできなかったことが原因。
通常、ユーザディレクトリ下の .wapi というディレクトリが作業用に使用されるが、apache 経由で nobody として起動されると、/.wapi を見に行こうとするため、不正終了。
しかし、このディレクトリは環境変数 MONO_SHARED_DIR で設定可能。ホームディレクトリ下にディレクトリを作成し、そこを参照させるようにしたところ、無事に CGI として動作。
/sbin/adsl-start の
Monitor connection
CGI に GET メソッドでデータを渡す場合、データの長さが制限されるが、この長さはサーバーの設定で変更できるようだ。Apache であればたぶん「LimitRequestLine」ディレクティブ。
参考ページ
私は apache と mono(linux 上で .net が使える環境) を使っているが、基本的に mono でプログラムを実行するには
mono targetprog.exe
#!/bin/bash mono targetproc.exe
しかし、C# では標準出力の文字コードが自動的に調べられ、Console クラスの Write メソッドではその文字コードにあわせて出力が行われるのだが、Console.Out.Encoding.BodyName を調べると CGI として呼び出された場合はどうしても us-ascii になってしまい、日本語を表示することができない(Console クラスが勝手に us-ascii でない文字を「?」としてしまうため)。
これを解決するには標準出力のバイトストリームを取得し、そこへバイト列に変換された文字列を書き込むようにする。例を挙げると
String str = "テスト文字列"; byte [] bytestr = Encoding.UTF8.GetBytes(str); Stream output = Console.OpenStandardOutput(); output.Write(bytestr, 0, bytestr.Length);
.net framework を使用したプログラムから ShellExecute 関数でプログラムを呼び出した場合、うまくいかないことがある。具体的には、グローバルフックしたプログラムから対象プログラムにメッセージを送り、対象プログラムでそのメッセージを処理しているときに ShellExecute を実行するとうまくいかないようだ。このとき、関数からは SE_ERR_ACCESSDENIED (=5) が返される。
.net framework を使用したプログラムをネットワークドライブに置いて実行しようとすると、セキュリティのエラーが発生して実行できない。これを回避するにはセキュリティを甘くしてやればよい。「管理ツール」から「Microsoft .NET Framework 1.1 構成」を選んで、「マイ コンピュータ」の「セキュリティ ポリシーを変更する」から「イントラネット」の信頼レベルを「完全な信頼」にすれば一応は動くようになる。ただし、他にどんなセキュリティ上の問題が出てくるのかは調べていない。まぁ、家庭内 LAN のレベルなら問題ないだろう。
今月はいろいろ大変だった。何が大変だったかはいずれ書くとして、今日の記事は IE のコンポーネントについて。
わけ合って IE のコンポーネントを使ったプログラミングをしているのだが、解析された HTML 文書.を見てびっくり。なんと、IE は HTML 文書を解析するに当たり様々な情報を勝手に補完しているのだ。たとえば、HEAD タグの無い文書に空の HEAD を足したりする。最も苦笑したのはそれぞれのタグで可能性のある属性をすべて補完していると言うこと。これは javascript 用の on~ といった属性まで補完してしまう。常識的に考えると、とんでもないリソースの無駄遣いといえよう。しかし、IE に同情したい気にもなる。というのも HTML の仕様が XML のように厳密ではなく、かなりあいまいだからだ。処理をする上では一度処理しやすいように補正したくもなるのだろう。それにしてもここまでしなくとも・・・。
<html><p>最初の行</p> <p>テスト<b>太字</b>テスト</p> <table border="1"> <tr><td>td1</td><td>td2</td></tr> </table> </html>
Visual Studio .net で ASP.NET Web アプリケーションプロジェクト をフォルダごと移動するには、1.「*.csproj.webinfo」ファイルをテキストエディタで開き、「Web URLPath」に適切な値を設定する。2.IIS の設定を開き、対象ディレクトリのプロパティの「ディレクトリ」タブでグレーアウトしている「アプリケーション名」の右にある「作成」ボタンを押す(そのあとアプリケーション名は削除してよい)。としなければならない。
マルチセッション接続をしたところ、xsltproc がインターネット上のリソース(http://www.parof.jp/~ と記述されたリソース)にアクセスできなくなり、エラーとなってしまった。おそらく DNS 関係のエラーだと思うのだが、修正すべき場所が分からないので当面はマルチセッション接続しないことにするしかない。
VC++ で dll の共有領域を作成するには
#pragma data_seg(".sharedata")
int global = 0;
#pragma data_seg()
LIBRARY
SECTIONS
.sharedata READ WRITE SHARED
共有名は習慣的に「.」で始まるようだ。また、「.」も含めて8文字以内にした方がよさそうである (*1) 。その他いくつか予約済みの共有名もある。MSDN ライブラリの「Visual C++ リンカ オプション」→「/SECTION(セクション属性の指定)」によれば、「.arch .bss .data .edata .idata .pdata .rdata .reloc .rsrc .sbss .sdata .srdata .text .xdata」が予約済みだ。
VC++ でバイナリファイルのエクスポートされるシンボル名を調べる方法。dumpbin コマンドにオプションとして「/exports ファイル名」をつける。
apache に GET メソッドでデータを与える際、与えたデータの最後が「.xml」だとそれ全体を URL として解釈してしまう。例えば「http://www.parof.jp/test.cgi?sample.xml」とした場合、「http://www.parof.jp/test.cgi?sample」という XML ファイルが呼ばれたものとして処理されてしまう。おそらく「.html」などでも同様だろう。ただ、これが正しい挙動なのかバグなのかは分からない。
xsltproc でバグと思われる現象を発見した。コメントノードに対して「xsl:number」で「level="any"」とすると正しくカウントされないようなのだ。まず一つは、カウントの開始値が「0」になってしまう点で、もう一つは同一の親ノードに属していると番号が同じになってしまうという点だ。IE では問題ないし、コメント以外でも問題ないのでバグではないかと思う。
私はコメントを文章中でまさにコメント、注釈として使っていて、xsl:number により番号を振っていたのでかなり痛い。面倒だが通常のタグに置き換えるしかないだろう。
ひさびさに Parof へリンクしているサイトを調査していたら、Jエントリーなるサービスに登録されていた。このサービスは「BIGLOBE」「EXCITE」「hi-ho」「ODN」「So-net」「DION」「サイボウズ」「@NetHome」のカテゴリにまとめて登録されるものだ。本来、登録審査料が 10500円 かかるはずなのだが、なぜか申請もしていないのに登録してくれていた。まったくもってありがたい話しである。でも「サイボウズ」と「@NetHome」はどこから検索できるんだろう。
やはり何とかしてサーバーサイドで XSLT 変換できないものかといろいろ調べたのだが、意外と身近なところにいい感じのツールがあった。libxsltに入っている、xsltprocというツールだ。引数に XSL ファイルと XML ファイルを与えてやれば変換した結果を出力してくれる。これをうまく CGI から呼び出せればうまくいくのではないか・・・。と、この xsltproc でいろいろ実験しているうちに気付いたことがある。このツールを使っても XHTML の変換にはやはり時間がかかるのだが、XML だとあっという間に終わってしまう。もしかして IE にしろこのツールにしろ、変換に時間がかかるのは XPath で属性を使っているからではなく、XMLT と XML との間に大きな違いがあるのではないか。で、結局分かったことは、DOCUTYPE宣言があるかどうかで速度が大きく変わるということだ。おそらく構文のチェックに時間がかかるのだろう。もちろん、これがないと XHTML はおろか HTML Valid にすらならないので、やはりサーバー側で何とか変換したい。
というわけで、早速簡単な CGI を組んで試してみた・・・。おぉ~~~!あっさりとうまくいってくれたではないか。これでようやく長旅の末に安息の地を得られた気分だ。それにしても、xsltproc の吐き出すソースはすさまじく汚い。いや XSL を忠実に適用するとこのようになるのかもしれない。にしても、まるで難読化ツールでも使ったかのごとくだ。
一通り作業も終わり、HTML 4.01 Transitional のチェックも Valid だった。ようやく安眠できそうだ。あ~疲れた。
また新しい動きがあった(というべきか?)。XHTML 化する前の文書が Google に検索されている。しかも、text/plain で返しているはずなのだが、どうも XML 文書として認識されているような気配だ。というのも、要約の部分に要素(エレメント)内のテキストだけ表示されているからだ。う~~~ん・・・、いったいどうしたらいいんだろうか。もうわけわからん。
方針も決まり、XML 化していた一部ページをやっとこさ XHTML に書き直した。タグの意味はそれほど重要ではないので、自分の欲しいタグが無いものについては class 属性で実際の意味づけを行った。例えば div の class 属性が sec ならそれはセクションを表す、といった具合だ。そして XML と XSLT 対応のクライアントであれば実際のデザインは別に記述した XSLT が使われる。
文書としては XHTM 1.0 strict valide だし、HTML としてもおおむね閲覧可能 (*3) になっていて、Acction で登録された cgi により XML に対応していないクライアントへは text/html として提示するから Google の検索にも引っかかるだろう。
が、またしても問題が発覚した。ページの表示がやたらと遅いのだ。最初はいろいろなウィンドウを20個前後も起動していたため、動作が不安定になったのだろうと思ったのだが再起動しても同じだった。しかもこれは IE だけで、mozila ではきちんと高速に表示される。察するに IE の XSLT パーサーが低性能なのだと思う。以前に比べると、意味づけを要素名ではなく class 属性で行っているため XPath の評価式はより複雑になってしまっているので、それが原因だろう。となると私は一体どうしたらいいのだ?!
text/plain でなんとかうまくいくだろうと思ったものの、まだなんとなく釈然としないのでいろいろ調べてみた。すると、Google で text/xml であっても XML 文書が検索された。こないだは検索されなかったハズなのだが、見落としていたのだろうか?いや、それにしても今回はかなりの数が検索に引っかかっている。前回もこれらすべてを見落としたとは考えにくいのだが・・・。まぁ、しかし、変な小細工をしなくても検索に引っかかることがわかった。
しかし、重大な問題が見つかった。丹念に調べると、私のページも見つかったのだが、text/xml で返される他のページにしても text/plain で返される私のページにしても、Google での順位が極めて低いうえに、「ファイルタイプ:不明」でしかも紹介文(要約)が全くでてこないのだ。しかも、そのページに含まれているいろいろな語句で検索にかけてみるのだが、どのようなキーワードが対象になっているのか皆目検討がつかない。これは要するに、Google が XML をあまり重要視していないということなのだろう。
しかたがないので、ようやく XHTML で記述する決心がついた。XHTML といえど XML 文書であることには変わりが無いのであとからデータ処理する上で困ることもないだろう・・・
XML 文書であっても強制的に text/plain とすることで Google に引っ掛けさせようと思ったのだが、重大な事実に気付いた。Content-Typeはブラウザにデータの種類を教えるためのヘッダだ。ならば IE でこそうまく表示できたがこれは本来、正しい動作ではないのではなかろうか?他のブラウザだとどうなるだろう?というわけで、Mozila で試した。で、はやり予想通り完全にタダのテキストとして表示されてしまう。これはさすがにマズい。こちらが仕様どおりにしていてブラウザが対応していないのならともかく、明らかにこちらの対処が間違っている。
なんとか Google のロボットだけ text/plain を返して、残りのブラウザでは text/xml を返すようにはできないか?と、ここで Google ロボットの挙動を正しく理解してみることにする。具体的には、アクセスログをとってブラウザ側から送られてくるAcceptヘッダ (*1) を分析してみる。早速 CGI を仕掛け、さて数日待つかと思ったのだがわずか3時間ほどで Google のロボットが4件も引っかかっていた。なんとまぁ・・・。
何はともあれデータは入手できた。それによれば、やはり Google はtext/htmlとtext/plainだけが Accept ヘッダに記述されていた。これで、ここまでモヤモヤしていた疑問がスッキリとした。検索エンジンのロボットにしろブラウザにしろ、この Accept ヘッダとサーバが返す Content-Type が重要なのだ。
これで方針は決まった。ブラウザが送ってくる Accept ヘッダに text/xml か */* が含まれていたら Content-Type: text/xml として送り返し、含まれていなかったら Content-Type text/plain で返すのだ。というわけで、Apache をいじくりまわしてみた。
結論から言うと、Apache に用意されている標準的なモジュールでは解決できなかった。で、あれこれ試して最終的にはmod_actionsモジュールを使って CGI に処理させることにした。簡単に書くとこれはActionディレクティブで指定されたタイプの文書が要求されたら、指定された CGI に処理を移すというものだ。しかも、結局この方法が一番簡単だった。これで Google のロボットが拾ってくれればよいのだが・・・。 (*2)
Cocoon は面倒なうえに期待通りの動作をしてくれる見通しが立たないので、あきらめて XHTML にしようと思った。それにしてもどうして IE は XHTML を正しく処理できないのだろう?それに、中には XHTML で拡張子が xml でも正しく表示しているページがあるのだ。
と、あることに疑問を感じた。ローカルなファイルは拡張子で xml か html(xhtml) かを判別していて、xml 文書としてだと正しく処理されないと言う現象がおきる。では、インターネット上のファイルはどのように識別しているのだろうか?既述のとおり、拡張子が xml でも正しく表示されるページがあるのだから、何か方法があるはずだ。
で、これは案外早く思いついた。CGI を作ったことのある人なら分かると思うが、HTTP プロトコルでサーバやブラウザが通信する場合、文書本体に先立ってその種類をあらわすContent-Type: text/htmlなどの情報が送られる。
もしかすると、text/html の部分が違うのではなかろうか。そう思い、早速、telnet でオーソドックスな HTTP プロトコルによって正常に閲覧できるページにアクセスしてみると、やはり text/html で返ってきている。では、自分のサーバーはどうか。ビンゴ!返されていたのは text/xml だった!
これはひょっとして Google も同じ理由で引っかからないのではなかろうか。というわけで、サーバーの設定を変更し、拡張子が xml でもプレーンテキスト、つまり text/plain を返させ、もうしばらく様子を見ることにした。
今日はサーバーサイドで XML に XSLT を適用し、HTML に変換する方法を考えてみた。どうやら
というわけで、早速インストール。しかし、前もって必要なものが多すぎる。そもそも Cocoon は
で、無事インストール完了したのだが・・・、どうも私の期待する動作はしてくれないようだ。というのも、私は *.xml 文書が要求されたら Cocoon で処理が行われる、というのを期待していたのだが、Cocoon は Servret の性質上、決められたディレクトリ下の文書しか変換してくれないのだ。う~む、どうしたものか・・・。
一部のページを XML 化してからだいぶたつが、Google がこのページを含む XML 文書を一向に拾ってくれない。以前は例えば「VisualStudio.NET ではじめる C言語」のようにそのページしかありえないキーワード(というか文章?)をいれれば間違いなくトップでヒットしていたのだが・・・。しかも、XML 化した5ページすべてが同じ状態。
XML 化する前に Google に「XML 文書は検索対象になるか?」とたずねたところ「なる」という回答だっただけに落胆の程は大きい。で、いろいろ調べてみると「XHTML 文書は検索されている」ことに気付き、そのむねもう一度 Google に聞いてみたのだが、やはり回答は同じだった。加えて、「常にお客様のご希望に添えるとは・・・」というお決まりの文句まで添えられており、ショックの度合いを深めたのだった。
しかし、いつまでもほうっておくわけにも行かないので XHTML 化を試みることにした。が、作った文書を Internet Explorer で見ようとすると.のようなエラーが出て表示できない。いろいろ調べてみると、どうやら MSXML ライブラリのバグらしく、XHTML のバージョン 1.0 は大丈夫だが、バージョン 1.1 はこういった問題があるらしい。だが、拡張子を html にするとなぜか見える。XHTML 1.0 で作ってもよいのだが、最新の正式なバージョンが使えないと言うのはなんだか気持ち悪い。ということで、明日は サーバーサイドで XML を HTML に変換する方法を考えてみることにする。
使用する前にパラメータ エンティティを定義しなければなりません。リソース 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd' の実行エラーです。ライン 85、位置 2
%xhtml-prefw-redecl.mod; -^