« 2007年1月 | トップページ | 2007年7月 »

2007年6月

2007年6月26日 (火)

デフォルトオブジェクト

今回はデバイスコンテキストのデフォルトオブジェクトについて。

昔、MSDNのどこかのページでこのデフォルトオブジェクトについての記述を見たような記憶があるのだが、あらためて捜してみると見つからない(見つかったらリンクを貼ろうと思っているが)。仕方がないので、他のサイトを参考にすると、デバイスコンテキストには、デフォルトオブジェクトとしてストックオブジェクトの黒のペンと白のブラシが選択されているそうなのでこれを確認してみる。デバイスコンテキストに現在選択されているオブジェクトのハンドルはWin32APIのGetCurrentObjectで取得できる。また、ストックオブジェクトのハンドルは同じくGetStockObjectで取得できるので、これらのAPIによって返されるハンドルをWM_PAINTメッセージの処理内で表示してみた。

Defobjects1

上段がペンについて。引数にOBJ_PENを指定してGetCurrentObjectで現在選択されているペンオブジェクトのハンドルと引数にBLACK_PENを指定してGetStockObjectでストックオブジェクトの黒のペンのハンドルを表示した。確かにハンドルが一致する。

下段がブラシについて。ペンと同様に引数にOBJ_BRUSHを指定してGetCurrentObjectで現在選択されているブラシオブジェクトのハンドルと引数にWHITE_BRUSHを指定してGetStockObjectでストックオブジェクトの白のブラシのハンドルを表示した。こちらもハンドルが一致する。

一番下の図形はデフォルトのペンとブラシを使ってWin32APIのRectangleを使って描画した矩形である。確かに輪郭が黒で内部が白で塗りつぶされている。

最後にフォントについて。フォントはストックオブジェクトのSYSTEM_FONTフォントが選択されるそうなので、同様に試してみた。結果は下の通り。

Defobjects2_1

現在選択されているフォントオブジェクトのハンドルは引数にOBJ_FONTを指定してGetCurrentObjectを呼び出せば取得できる。

ちなみに、デバイスコンテキストには厳密にはクラスデバイスコンテキスト、コモンデバイスコンテキスト、プライベートデバイスコンテキストの3種類があるが、ここでは、コモンデバイスコンテキストを扱った。

2007年6月25日 (月)

最近暑い。

最近暑くて色々集中できない。ブログの更新もまた1週間空いてしまった。というより、ネタがすぐ尽きる。ちょこちょこ色々やっているが、ネタにするほどのことをやっているわけでもないし・・何をやっているかというと、GDI(Graphic Device Interface)のもっと基本的な部分。Oracleのネタもないしな。趣味でやっているから、興味のないことやりたくないし。うーん。

2007年6月17日 (日)

HDDがほしい。

タイトルだけ書いて思わず投稿してまった・・

タイトルどおりHDDを買おうかなと思ってる。最後にHDDの値段を調べたのは確か半年以上前。今は500GBクラスのHDDでも1万ちょいなんね。安い。ちなみに、自分のマシンのHDDは80GB×2で計160GB。まぁ、シビアに困ってはいないんだけど。新しく買うならやっぱSATA HDDだ。遂に念願のSATAか?。自分のHDDは未だにIDEだから、たまに、パソコンのパーツがおかしくて交換するときに、内部の配線とくに幅広のIDEケーブルがじゃまでしょうがいない。結構前(2年以上前くらい?)からSATAケーブルの細さにあこがれていた。パソコンのパーツはちょっとずつ取り替えていって、半年前にSATA対応のマザーボードに変えたので後1歩。今なら垂直磁気記録のHDDがいいのかもね。容量は300GBか500GBクラスでいいかな。もうちょっと、調べてみるかな。

そういえば、調べてたらフラッシュメモリを使ったSSD(Solid State Disk)なんてものが今売られているのか。でも、書き込み可能回数が1万とか10万回なんだけど、そんなんで、システムドライブでの使用に耐えられるのか?

2007年6月15日 (金)

フォントの列挙

今回はフォントの列挙。

Windowsではフォントを列挙するAPIとしてEnumFonts、EnumFontFamilies、EnumFontFamiliesExが用意されているが、MSDNによると、前の二つは16bit版の互換性のために用意されているそうなので、ここでは、EnumFontFamiliesExを使うことにするが、このAPIを使ってフォントを列挙してみる。ここでは、フォントダイアログの一覧に列挙されているフォントの一覧を取得してみる。

Enumfont1_1

EnumFontFamiliesでは、第2引数として渡すLogFont構造体のlfCharsetとlfFaceNameフィールドによって、列挙するフォントを制御するが、まずは、それぞれにDEFAULT_CHARSETと空文字列を設定して、すべて列挙してみる。結果は下の通り。

Enumfont1_2_7      

フォントタイプは、コールバック関数の第3引数として返されるFontTypeを使ってフォントの種類(ラスタフォント、ベクタフォント、TrueTypeフォント(OpenTypeを含む))かを判断している。タイプフェイス名(フォントファミリ名)には、第2引数として返されるNewTextMetricExのelfLogFontのlfFaceNameフィールド、文字セットにはNewTextMetricExのelfLogFontのlfCharset、スクリプトにはEnumLogFontExのlfScriptの値を表示している。

MSDNの説明にもあるように、lfCharsetにDEFAULT_CHARSET、lfFaceNameに空文字列を設定するとすべてのタイプフェイスのすべての文字セットが列挙されているのがわかる。で、これをいかにフィルタするかが、肝である。

先ほどの結果をどうフィルタするかだが、タイプフェース名が重複する行を排除すればまず問題ないであろうが、MSDNのCreateFontのfdwOutputPrecisionパラメータの説明にあるように、種類の異なる同じ名前をもつフォントがある可能性があるので、(フォントタイプ、タイプフェース)の組で重複する行を排除したほうがよさそうである。実行結果は下のとおり。

Enumfont1_3

自分の環境ではリストアップされたタイプフェースは50個であった。そして、すべてのフォントを表示するように設定したフォントダイアログでも50個のタイプフェースがリストアップされたのでよさそうである。まぁ、このAPIについてはあまり深入りするつもりはないのでここまで。参考までに、英語であるが、ここここここを読んでみるといいかもしれない。

最後に、タイプフェースとフォントの違いについて触れておく。タイプフェースとは、同一の書体を持つフォントのグループのことである。参考にあげた記事の中でも触れているが、例えば、Arialタイプフェースについて見てみよう。Arialタイプフェースには、スタイルに応じて、4つのフォントが用意されている。標準スタイルのArialフォント、太字スタイルのArial Boldフォント、斜体スタイルのArial Italicフォント、太字・斜体スタイルのArial Bold Italicである。「コントロールパネル」->「フォント」からそれを確認できる。

Enumfont1_4

これら、スタイルの異なる4つのフォントがグループ化され、Arialタイプフェイス(一般的な用語を使うとArialフォント)と呼ばれているのである。ちなみに、上の画面でArial Blackとあるが、これは別グループでArial Blackタイプフェイス(Arial Blackフォント)と呼ばれる。また、MS Sans Serifはベクタフォントであるが、TrueType以外のフォントはフォント名とタイプフェース名が同じになる。また、日本語のWindows環境でよく使うフォントとして、MS ゴシックなどがあるが、通常スタイルのフォントしか用意されていなく、他のスタイルを指定したときは、GDIのラスタライザがエミュレーションでグリフのビットマップを作りだしているようである。なにせ、漢字など収録字数が多いので、各スタイル用のフォントを作るのは大変だからなのかもしれない。

2007年6月14日 (木)

コードページの続き

引き続きコードページのお話。

前回作成したプログラムを動かしてたら、IsValidCodePageでtrueが返ってきてるのに、GetCPInfoExで、情報が取得できてないコードページがあるのに気づいた。次のように。

Cp2_1_7   

うーむ。小一時間色々調べたがよくわからない。で、GetCPInfoExの戻り値をチェックしてなかったので、エラーが発生したらGetLastErrorで拡張エラー情報を表示するように、プログラムを変えてみた。

Cp2_2_2

MSDNの説明のとおり、GetLastErrorでERROR_INVALID_PARAMETER(87)が返ってる。で、あることに気づいた。MSDNの説明でコードページに関して「インストール済み(installed)」または「利用可能な(available)」と表現を使い分けている。で、もう一度、GetCPInfoExの説明を詳しく見ると、

コードページは、システムにインストールされている場合にのみ、有効と判断されます。」

英語版では

A code page is considered valid only if it is installed on the operating system

とある。IsValidCodePageはコードページがシステムにインストールされているか判断するのであって、インストールされていても利用可能であるとは限らないのだ。まぁ、詳しくはわからないが、コーディングする時は要注意だ。

で、今まではWindows2000上で作成したプログラムを動かしていたが、XP上で動かしてみた。

Cp2_3_1

XP上では(デフォルトで?)利用可能なコードページが増えている。コードページ54936のGB18030は中国の文字コードであるらしいが、MaxCharSizeが4でLeadByteが空である。GB18030はどんな文字コードか調べようとグーグルで検索すると、中国政府がメーカーに強制的に採用を義務づけたとかおもしろい話も見つかる(参考1参考2)。まぁ、そんな話は置いといて、国際化アプリケーションを作成する場合、コードページをごりごり切り替えるより素直に内部の文字コードをUnicodeにした方が楽なような気がする。

で、最後に作ったアプリを簡単そうなのでここからダウンロードできるようにしようかなと思ってもみたり。気がむいたらだけど。

2007年6月13日 (水)

Windowsのコードページ

色々話題がぶっとんだりしてるが、まぁ、気にしないでおこう。

で、今回はWindowsのコードページ。現在一般的に使われてるWindowsの内部の文字コードはUnicode(UTF-16LE)になっているが、Unicode以前のさまざまな国・地域専用の文字コードとUnicode間の変換テーブルをコードページと呼び、コードページ識別子(Code Page Identifier)を割り振り管理している。日本語の文字コードに関して言えば、例えば、シフトJISには932というコードページ識別子が与えられている。で、今回は、そのコードページ関連のWinAPIであるIsValidCodePageとGetCPInfoEx(GetCPInfo)を色々試してみた。Windowsでは既に150以上(詳細はここ)ものコードページ識別子が定義されているが、それぞれのコードページに対して、上記のAPIがどのような結果を返すプログラムを作成してみた。実行結果は下図の通り。

Cp1_3

ちなみに、先ほど述べたシフトJISの2バイトで表される2バイト文字の先行バイト(リードバイト)の範囲は、0x80-0x9F、0xE0-0xFCであるが、確かに、上の図でも、(0x80-0x9F)(0xE0-0xFC)となっており結果はよさそうである。また、先行バイトはWin32APIのIsDBCSLeadByteを使っても調べられるが、こちらは、コードページを指定できない。CPINFOEX構造体のMaxCharSizeには、そのコードページ内の文字の最大バイト長が返されるが、シフトJISはDBCSなので、2が返されるのが上図からも分かる。DefaultCharとUnicodeDefaultCharはWideCharToMultiByteとMultiByteToWideCharでMBCS<->Unicode間の変換を行ったときに、変換できない文字に対して割り当てるデフォルト文字を明示的に指定しないときに使用される文字である。

とまぁ、詳細はMSDNを読んだほうが速いのでここまで。

追記:コードページを指定できるIsDBCSLeadByteExがありましたね

2007年6月11日 (月)

そうえいばDBXInspector

そういえば、DBXInspectorの最新版を2週間以内にアップロードする予定。それで、そろそろVectorに登録してみようかななんて思ったりもする。Vista対応ではVistaのUAC(User Account Control)がどう影響するか気になるが(動作確認するまではもちろんVista非対応で行こう)。すごいやる気がでてきた(今までやる気がおきなかったわけではなく、色々調査してたんだけど)。正式版でなくても、Vectorへの登録が第一歩だ。需要があれば、DBXInspectorから色々なデータベースに接続できるように、ADO版でも作ってもみようかなと。そうすれば、ADOドライバさえ用意すれば、OracleだろうとSQL Serverだろうと果てはIBMのDB2データベースだろうと接続できるし。DBXInspectorの大部分は利用できるので、そこまで大変じゃないかも。もちろん、Oracle特有の機能に依存してる部分ははずさなきゃいけないけど、グリッドとエディタ部分は既存のコードが利用できるだろうし。

2007年6月 8日 (金)

Vista用仮想PC

そういえば、Vistaを機能制限なしで30日間ためせるVirtualPC2007用の仮想イメージがMicrosoftのサイトからダウンロードできるようになったとのこと。

ちょっと、ダウンロードしようと思ったら、なんか登録が必要なのね・・orz。気が向いたら試してみようと思います。Microsoftの仮想PCソフトも無料です。

ちにみに、これらは主にクライアント向けの製品であるが、サーバー向けにはVirtual Serverという製品もある。

2007年6月 6日 (水)

Uniscribeの概要(2)

前回の続きである。

今回は実行単位(ラン)について書いてみる。Uniscribeは様々なスクリプトを処理するために、複数のシェーピングエンジンを用意しているが、ScriptItemizeはテキストをシェーピングエンジンの変わり目または読む方向の変わり目によってテキストを実行単位に分割する。Microsoftのタイポグラフィのサイトによると、少なくとも以下の10個のスクリプトエンジンが存在する???ようである。

  1. Standard Scripts
  2. Arabic Script
  3. Korean Hangul Script
  4. Hebrew Script
  5. Indic Scripts
  6. Khmer Script
  7. Lao Script
  8. Syriac Script
  9. Thaana Script
  10. Thai Script

スクリプトによって最低限必要な言語処理は変わると思うが、前回例に出した、アラビアスクリプトでどのような言語処理が走るか覗いてみる。

上記のサイトによると、以下のような処理が行われるそうである。

Uniscribeoverview2_1_2

ちなみに、前回、アラビア語では、文字の位置によって字形が変わる文字があると書いたが、その形式を

  • 単独形(isolated form)
  • 語頭形(initial form)
  • 語中形(medial form)
  • 語末形(final form)

と呼ぶ。

これらのアラビアスクリプトに必要な言語処理のグリフ置換を行っているのが、最初に示した図の1-bから1-eである。もちろん、日本語にこれらの処理は必要ない。ところで、日本語の処理にはどのスクリプトエンジンが使われるのだろうか??lol

また、標準Win32APIでグリフインデックスを直接処理する時と同様、フォントリンクなどは働かないので、ScriptShapeで欠損グリフが発生した時に、代替フォントを使って表示する必要があれば、自前で実装する必要がある。が、どうもExtTextOutやUniscribeのScriptString系のAPI内部で具体的にどのように代替フォントを探してるか知るよしもないので、それらのAPIと全く同じ結果を得ようとするのが大変らしい・・・

2007年6月 5日 (火)

Uniscribeの概要

まず、UniscribeのAPI一覧をMSDNなどで見ると分かると思うが、UniscribeのAPIは主に二つに大別できる。

  • ScriptString系のAPI
  • それ以外の低レベルAPI

まず、ScriptString系のAPIは高レベルのAPIで、プレーンテキストつまり同一スタイル(フォントやサイズや色などが同じ)のテキストを処理する時に使用するAPIである。様々な国や地域で使われるスクリプトを含むテキストはアプリケーション側が任意の位置で勝手に分割して処理すると適切な結果を得られない可能性があり、基本的には、行単位などで処理する必要があるが(ExtTextOutを使う時も同様)、エディタなどで見られるキーワードの色分け表示などをする必要がなく同一スタイルで表示する時に使用するAPIである。次に、ScriptString系以外の低レベルAPIは、色分け表示など複数のスタイルでテキストを処理するときに使用するAPIである。また、以前にGetCharacterPlacementを用いたカーソル位置の決め方のブログを書いたが、UniscribeにはそのためのScriptCPtoXやScriptXtoCP(ScriptString系はScriptStringCPtoX、ScriptStringXtoCP)といった便利なAPIが既に用意されている。

ScriptString系の使い方は引数が多いことを除けば、以外に簡単に使用できるので、ここでは主に低レベルAPIを扱ってみる。

主な描画の流れは以下のようになる。

  1. ScriptItemizeで、テキストを実行単位(ラン)に分割。
  2. 複数のスタイルでテキストを処理する必要があれば、1で得られた実行単位を更に細かい実行単位に分割。
  3. ScriptShapeでシェーピングを行いグリフと表示属性を生成。
  4. ScriptPlaceでポジショニングを行いグリフの有効幅と2次元オフセット情報を生成。
  5. ScriptTextOutで描画。

まず、シェーピングとは、主にテキスト文字列からテキスト文字列を表すグリフインデックスの列を生成する処理を指す。以前紹介したWin32APIのGetGlyphIndicesも与えらたテキスト文字列からグリフインデックスの列を生成するが、GetGlyphIndicesは言語毎に必要な言語処理のグリフ置換(Glyph Substitution)が行われない。通常、フォントファイルには、文字コードからフォントファイル内のグリフを識別するグリフインデックスへの対応を表すマッピングテーブルを持つが、GetGlyphIndicesは単純にこのマッピングテーブルを用いた変換を行う。ちなみに、OpenTypeフォントでは、このテーブルをcmapテーブルと呼ぶ。そして、言語によっては、適切な表示を得るためにこの変換の後に更に変換が必要でこの処理を言語処理という。例えば、アラビア語を例にとると、アラビア語の文字は、文字の位置によって、字形が変化するものがある。これに対応するためには、更にグリフを変換する必要があり、これがグリフ置換である。ちなみに、これを行うときに使用されるテーブルをOpenTypeフォントではGSUBテーブルと呼ぶ。

次にポジショニングであるが、これはその名の通り、生成されたグリフをどう配置するかを決める位置決めの処理である。

とりあえず、ここまで。

2007年6月 4日 (月)

そしてUniscribe

今まで色々やってきたが、Unicodeを使って様々な国や地域のスクリプトを適切に処理するには、どうもUniscribeを避けて通ることはできないような気がしてきた(表示するだけならExtTextOutで十分だと思うが)。で、前々から色々Uniscribeの事を調べているが、いかんせん、ネットを検索しても情報がほとんどない。英語の資料も見てるが、英語をスラスラ読み書きできるわけではないので、遅々として進まない。

とりあえず、国際化の情報として、Microsoftのサイト

の情報を一通り読んでみるといいかも。全部英語だけど。概要を把握するにはお勧めです。

それにしても先は険しそう。

2007年6月 2日 (土)

GetCharacterPlacementの続き

また、GetCharacterPlacementのお話である。前回、双方向テキストをETO_GLYPH_INDEXなしのExtTextOutで出力させてみたが、今回は GetCharacterPlacementを使って同じ結果を出力させてみる。 流れとしては、GetCharacterPlacementでGCP_RESULTS構造体のGlyphsフィールド、Dxフィールドにそれぞれグリフインデックスと隣接する文字セルの原点間の距離が返されるので、それらを使ってExtTextOut(ETO_GLYPH_INDEXつき)で描画してみる。ちなみに、扱うテキストは前回と同じ。フォントはTahoma。

まずは、XP上での実行結果から。

Gcp1

前回の結果と見比べるとわかると思うが、XP上でのETO_GLYPH_INDEXなしのExtTextOutの実行結果と同じである。

次は、2000上での実行結果。

Gcp2

これは、XP上でのETO_GLYPH_INDEXなしのExtTextOutの実行結果と同じである。

やはり2000上で双方向テキストというかコンプレックススクリプトを正しく扱うには、Uniscribeを使うしかないようである。ちなみに、上の二つの図では、GetCharacterPlacementを呼び出すときに、GCP_REORDERと GCP_GLYPHSHAPEフラグを指定した。

ちなみに、この時のCaretPosフィールドで返されるカーソル位置は下の図のとおり。

Gcp3 Gcp4

左がXP上、右が2000上での実行結果。XP上でアラビア語の部分が右から左に表示されたように、カーソル位置のX座標がアラビア語の部分で減少していくのがわかる(82->78->78->61->56->49->49)。ここまでは、問題なさそうである。

次に、テキストを「ABCあいうえおABC」に変えてみる。フォントは同じくTahoma。

まずは、XP上の実行結果から。

Gcp5

次に2000上の実行結果。

Gcp6_1

まず、前にも書いたが、Tahomaは欧文フォントで日本語のグリフが存在しない。また、グリフインデックスを直接処理しているので、フォントリンクなどは働かないので、日本語の部分は文字化けするであろうと想定されたが、XP上ではグリフが存在しない時の代替グリフすら表示されていない。 2000上では矩形のグリフが表示されたが、3つ目と4つ目の矩形だけがくっついて微妙である。

うーん。

2007年6月 1日 (金)

Unicodeと双方向テキスト

今回は双方向テキストである。初めに、自分はこの方面に詳しくないので、用語の使い方や説明が適切でないかもしれないのでご勘弁を。また、詳しいことは別のサイトにお任せするとして、ここでは、Windows絡みのお話を。

Unicodeは世界の様々な国・地域で使われる言語のスクリプトを収録した文字コードの規格であるが、Unicodeを使ってプログラミングを始めると、日本人には馴染みの薄い問題に出くわす。その中の一つにテキストの双方向性がある。日本語を読み書きする方向はは通常左から右(縦書きというのもあるが)であるが、アラビア語やヘブライ語は通常、数字は左から右、その他の部分は右から左に読み書きする。で、Unicodeを使ってこれら複数のスクリプトが混在するテキストを自前で正しく表示・処理するとなるとややこしい。

WindowsではXP以降標準のAPIでこららコンプレックススクリプト(Complex Script)を正しく処理できるようになったそうなので、それを確かめてみる。(ちなみに、XP以前でもUniscribe(Unicode Script Processor)というAPIを使用すれば、コンプレックススクリプトを正しく処理できるそうであるが、詳しい事はここでは割愛する)

まずは、扱うテキストは次の図のテキストである。

Bidi1

これは、17のコードポイントで表されるテキストを1コードポイントずつ左から右に並べて表示したときの図である。両端の英語の「Hello」「World」のフレーズの間にアラビア語のフレーズがはさまれているテキストである。

次に、このテキストを正しく方向を考慮して表示したときの図が下の図である。

Bidi2

これは、Uniscribeを使いUnicode双方向アルゴリズムにしたがって、テキストを表示したときの図である。分かりずらいかもしれないが、両端の英語の部分は左から右へ、中央のアラビア語の部分は右から左に表示されている。つまり、中央の部分はテキストのメモリ上での格納順序である論理順序(Logical Order)とテキストの表示順序(Visual Order)が一致しないのである。

で、これらを元にWindowsの標準テキストAPIであるExtTextOutを使って(ETO_GLYPH_INDEXなし)で表示してみる。

まずは、Windows2000上での結果から。

Bidi3

先ほどの結果と照らしあわせれば分かると思うが、方向が考慮されず、中央のアラビア語の部分も両端の英語の部分と同様、左から右に表示されている。

次は、WindowsXP上での結果。

Bidi4

上の図のように、Uniscribeの結果と同じように、中央のアラビア語の部分が右から左に表示されている。

ちなみに、Unicodeでは、文字ごとに文字の方向属性という属性が定められていて、それらはWindowsAPIのGetStringTypeExを使って取得することができる。

GetCharacterPlacementとカーソル配置

うーん。ブログの更新が随分とあいてしまった。そういえば、GYAOで無料配信をしているスターゲートシリーズがおもしろい。続きをみたいところだけど、GYAOで続きが配信されるか疑わしい。なんか、最初のエピソードだけ流して興味あったら、レンタルするなりしなさいってスタンスのような気がする。

気を取り直して今回は、カーソル(キャレット)の配置。Windowsの標準コントロールであるEditコントロールみたいな機能を自前で実装するとなると、テキストの表示にはExtTextOutなどを使うとして、カーソルの位置をどうやって決めるかちょっと考えさせられる。以前、取り上げた、GetTextExtentExPoint、GetTextExtentPoint32やGetCharWidth32でできないことはないかもしれない。ちなみに、MSDNのドキュメントにも書いてあるように、文字列の幅を求めるのに、GetCharWidth32で個々の文字の幅を求めて、その和をとるのは、正確ではない。なぜなら、デバイスによってはカーニング等が行われるからだ。

で、こんな時に便利そうなのがGetCharacterPlacementである。GetCharacterPlacementのGCP_RESULTS構造体のCaretPosフィールドにカーソル位置の情報が返される。この情報の示す位置にカーソルを配置すればよいのだ。

で、さっそく、CaretPosフィールドに返された位置に線を引いてみたのが下の図である。

Caretpos1_3

フォントはMS ゴシックである。上の図のように、CaretPosフィールドに返される位置にカーソルを配置すれば、問題なさそうである。

ちなみに、上の図は、テキストをExtTextOutのETO_GLYPH_INDEXなしで表示したものである。GetCharacterPlacementのドキュメントを見れば分かるように、このAPIで、グリフインデックスも取得できるので、グリフインデックスを取得し、ExtTextOutでETO_GLYPH_INDEX付きで表示しても問題なさそうである。下がETO_GLYPH_INDEX付きで表示したときの図である。

Caretpos2_1

問題なさそうである。しかし、ここでフォントをTahomaに変えてみよう。結果は下のようになる。

Caretpos3_1

カーソル位置がおもいっきりずれているのが分かるであろう。まず、文字化けを起こしているが、これは、Tahomaは欧文フォントなので、日本語で使用するグリフが含まれていない。また、ETO_GLYPH_INDEX付きでグリフインデックスを直接処理しているので、フォントリンクが働かないので文字化けが起きているのである。(つまり、ETO_GLYPH_INDEXなしの時にExtTextOutで自動で行われるフォントリンクのような機能は自前で実装する必要がある)。この文字化けは、ある程度想定?できた結果なのでスルーして次の問題に進んでみる。

次の問題とはカーソル位置がずれていることである。ううーん。このカーソル位置はいったい何の位置なのだろうか・・これは、ETO_GLYPH_INDEXなしでExtTextOutを呼び出した結果を重ねてみれば一目瞭然である。

Caretpos4_1

上の図をみれば、わかるようにCaretPosで返されるカーソル位置は常にフォントリンクの影響を受けるということらしい。まぁ、これはそういう仕様と割り切るしかない。

追記:どうやら、上の現象はWindowsXP上では、異なる結果になる模様です。汗汗。ちなみに、上の現象はWindows2000上。

« 2007年1月 | トップページ | 2007年7月 »

自作ソフトウェア

無料ブログはココログ

メモ