tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルWindowsのシステムで使用しているフォントの取得。
記事No14274
投稿日: 2009/11/19(Thu) 14:16
投稿者ヨシ
開発環境 VB6
Windows XP Pro SP2(日本語)

Windowsのフォーム、メッセージボックスでの表示に使用されているような
システムのフォントを取得する方法があったら教えていただけますでしょうか。

まず、GetStockObjectを使用してフォントを取得します。
そして、テキストボックス等のコントロールにそれを設定して
自動的に文字化けを回避する仕組みをつくろうとしておりました。

しかし、作成したものを中国語OSで実行するとGetStockObject
はMS PGothicを取得してしまいます。
したがって、MS PGothicをフォントに設定したテキストに
中国語文字列を貼り付けると文字化けしてしまいます。

(下記のような手順でフォント名を取得しました。
 他の引数(DEFAULT_GUI_FONT以外)でもハンドル値は異なるものの、
 フォント名は全てMS PGothicでした。)

dim lngFont as long

lngFont = GetStockObject(DEFAULT_GUI_FONT)
Label1.Font = lngFont             '=25821221
msgbox Label1.Font                '=MS PGothic


使い方の誤り、もしくは他に良い方法がありましたらご指摘、ご教授お願いいたします。

[ツリー表示へ]
タイトルRe: Windowsのシステムで使用しているフォントの取得。
記事No14275
投稿日: 2009/11/19(Thu) 14:46
投稿者花ちゃん
> Windowsのフォーム、メッセージボックスでの表示に使用されているような
> システムのフォントを取得する方法があったら教えていただけますでしょうか。
Win32 API 関数の SystemParametersInfo を使えば取得する事ができるとは
思うのですが?。

> 中国語文字列を貼り付けると文字化けしてしまいます。
下記等は承知されておられるのでしょうか?
http://hanatyan.sakura.ne.jp/patio/read.cgi?no=64

[ツリー表示へ]
タイトルRe^2: Windowsのシステムで使用しているフォントの取得。
記事No14278
投稿日: 2009/11/19(Thu) 18:06
投稿者魔界の仮面弁士
> > 中国語文字列を貼り付けると文字化けしてしまいます。
> 下記等は承知されておられるのでしょうか?
> http://hanatyan.sakura.ne.jp/patio/read.cgi?no=64

そのページで紹介されている www.ocv.ne.jp は既に無くなっているので、
下記のように読み替えてください。m(_ _)m

> http://www.ocv.ne.jp/~oratorio/junk/image/UnicodeDG.jpeg
http://www.vb-user.net/yaplog/images/UnicodeDataGrid.jpg

> http://www.ocv.ne.jp/~oratorio/windev/vb/UnicodeDataGrid.cab
http://www.vb-user.net/yaplog/bin/UnicodeDataGrid.cab
http://www.vb-user.net/ocv/UnicodeDataGrid.cab

> http://www.ocv.ne.jp/~oratorio/windev/vb/UnicodeTextBox.lzh
http://www.vb-user.net/junk/replySamples/2003.06.17.01.51/UnicodeTextBox.lzh
http://www.vb-user.net/ocv/UnicodeTextBox.lzh

[ツリー表示へ]
タイトルRe^3: Windowsのシステムで使用しているフォントの取得。
記事No14280
投稿日: 2009/11/19(Thu) 19:28
投稿者魔界の仮面弁士
≫2009.11.19 URL 修正

多謝 m(_ _)m

[ツリー表示へ]
タイトルRe^4: Windowsのシステムで使用しているフォントの取得。
記事No14287
投稿日: 2009/11/20(Fri) 15:09
投稿者ヨシ
花ちゃん様、仮面弁士様
ご回答ありがとうございます。

現状を説明していながら、いろいろ説明が足りなかったようで
もうしわけありません。

現在、VC6++で作成したDLLに、例えば中国語の表示文言とフォント名を
持たせて、VB6で作成したEXE起動時にそれらを読み込み、VB6の各コントロール
のFontにDLLから取得したフォント名をセットすることで文字化けを回避しています。

そして今やりたいことは、DLLに設定されたフォントが該当のOSにインストール
されていなかった場合、システムのフォントを取得して、それを各コントロールの
Fontに設定することで、文字化けしないようにしたいと考えています。
DLL側は値のみを持たせているためVB6でこれらを実現したいです。


>> Windowsのフォーム、メッセージボックスでの表示に使用されているような
>> システムのフォントを取得する方法があったら教えていただけますでしょうか。
>Win32 API 関数の SystemParametersInfo を使えば取得する事ができるとは
>思うのですが?。

アドバイスありがとうございます。早速このAPIを使ってみました。
日本語OSでは、システムフォントを取得しバイト型のまま(LOGFONTのlfFaceNameを)
各コントロールのFontに値を渡すと期待通りフォントが変更されました。
しかし、中国語OSで同様の処理を行っても、うまくいきませんでした。
バイト型のまま渡しているので取得したフォント名が内部で文字化けを起こした等は
ないと考えております。
何が原因なのか現在見当が付いていない状態です。

対応策、また誤った解釈等ありましたらご指摘いただけますでしょうか。
お手数ですが、よろしくお願いいたします。

[ツリー表示へ]
タイトルRe^5: Windowsのシステムで使用しているフォントの取得。
記事No14288
投稿日: 2009/11/20(Fri) 16:08
投稿者ヨシ
> 日本語OSでは、システムフォントを取得しバイト型のまま(LOGFONTのlfFaceNameを)
> 各コントロールのFontに値を渡すと期待通りフォントが変更されました。

すみません。訂正があります。
日本語OSでバイト型のまま各コントロールのFontに値を渡した場合、
期待通りフォントが変更されたと書きましたが、変更されていませんでした。
大変失礼いたしました。

したがって、各コントロールのフォントに取得したシステムフォントを設定したい場合
は、chrを用いてバイト型から文字列に変換する必要があるようです。
英語版と日本語版ではそれぞれ取得できるシステムフォント名がどちらも英文字だけで
成り立っているので文字化けせず、コントロールのFontに値を渡せば正常に動作しますが
中国語版の場合、chrで変換した時点で"?"が混じった化けた状態のフォント名に
なってしまいます。これが設定できない理由のようです。
つまり、フォント名を文字化けさせずに中国語版でこれを実現したい場合は、
中国語版のVisualStudioで開発を行う必要があるということでしょうか。

お手数ですが、よろしくお願いいたします。

[ツリー表示へ]
タイトルRe^6: Windowsのシステムで使用しているフォントの取得。
記事No14289
投稿日: 2009/11/20(Fri) 17:44
投稿者魔界の仮面弁士
画面上で使用可能なフォントは、
 List1.Clear
 With Screen
  For n = 1 To .FontCount - 1
   List1.AddItem .Fonts(n)
  Next
 End With
のようにして一覧できます。“DLLから取得したフォント名”が、
この中にあるフォント名と一致しているかどうか確認してみてください。

なお、VB6 の標準コントロールは Unicode に対応していませんので、
使用可能な文字集合は、言語設定に依存することに注意してください。

また、コントロールの Font プロパティを設定する際には、
.Font.Charset の指定も必要になりますので、お忘れなく。


> > 日本語OSでは、システムフォントを取得しバイト型のまま(LOGFONTのlfFaceNameを)
> 日本語OSでバイト型のまま各コントロールのFontに値を渡した場合、
> 期待通りフォントが変更されたと書きましたが、変更されていませんでした。
API に文字列を渡すときには、ANSI版/Unicode版 いずれの API を使うかによって
コーディングが異なってきます。

実際に、どのようなコードを記述しているのかを明記してみてください。

今の状態では、コードに問題があるのか、記述に問題があるのか、環境依存の
問題なのか判断ができませんが、コピー & ペーストで検証可能なコードが提示されれば、
第三者によるテストが可能となるでしょう;少なくとも「日本語 OS」上でのテストが。


> 中国語版の場合、chrで変換した時点で"?"が混じった化けた状態のフォント名に
たとえば何という数値を、どの文字に変換しようとしていますか?
また、変換した結果をどのようにして確認しましたか?
(VB 標準の TextBox/Label/MsgBox 等では、多言語文字を表現できません)

Unicode 版 API が使えるなら、Chr 変換は不要かと思います。もし変換するにしても、
正しい文字であれば ChrW/AscW はほぼ損失無く相互変換できるはずです。

ANSI 版 API の場合には、StrConv に vbUnicode を渡すことで、
ANSI バイナリを VB の文字列に変換できるかと思います。
念のため、StrConv の第三引数も指定しておいた方が良いでしょう。
(私自身は、中文版で検証した事はありません)


なお、各国語版のアプリ生成のために、IPDK も提供されていたりします。
残念ながら、SP6 対応版は提供されなかったようですが…。
http://msdn.microsoft.com/ja-jp/library/cc765234.aspx

[ツリー表示へ]
タイトルRe^7: Windowsのシステムで使用しているフォントの取得。
記事No14294
投稿日: 2009/11/24(Tue) 17:54
投稿者ヨシ
ご返信ありがとうございます。

下記のようなコードで動作確認をしています。

Private Const LF_FACESIZE = &H20

Private Type LOGFONT
    lfHeight                    As Long
    lfWidth                     As Long
    lfEscapement                As Long
    lfOrientation               As Long
    lfWeight                    As Long
    lfItalic                    As Byte
    lfUnderline                 As Byte
    lfStrikeOut                 As Byte
    lfCharSet                   As Byte
    lfOutPrecision              As Byte
    lfClipPrecision             As Byte
    lfQuality                   As Byte
    lfPitchAndFamily            As Byte
    lfFaceName(LF_FACESIZE)     As Byte
End Type


        dim strResult as string
        dim lngRet as long
        dim A as LOGFONT
        dim i as integer

      'システムフォントを取得
    lngRet = SystemParametersInfo(31, Len(A), A, 0)

    '取得したフォントをバイトからストリングへ
    For i = 0 To 32    
        strResult = strResult & Chr(A.lfFaceName(I))        
    Next i
  
    Text1.Font.Charset = 128
    Text1.Font = strResult


日本語OSでこれを実行すると、Text1.Fontに MS UI Gothicが
セットされ、文字のフォントが変更されます。
中国語OSでこれを実行すると、文字のフォントは変更されますが、
中国語を貼り付けると文字化けします。
(現仕様では、SimSunなどのフォントをあらかじめ各コントロールのフォント
に設定しておけば正常に表示できています。)

A.lfFaceName に格納される値は、バイト型で下記になります。


183
76
63
182
174
182
192

中国語OSで、プリントアウトで出力された変換後のstrResultの値は
·L??R?A  
です。

中国語OSのシステムフォント名が2バイト文字であることが、
フォント名文字化けの原因ではないかと考えております。(おそらく「微軟正K體」)



また、下記のようなものも試してみました。


    lngRet = SystemParametersInfo(31, Len(A), A, 0)
    font1 = CreateFontIndirect(A)
    ret = SelectObject(Form1.hdc, font1)
    ret = DeleteObject(font1)
    Text1.Font = Form1.hdc

これを日本語OSでおこなうとき、
Text1.Font.Charset = 128
を実行した場合はMSPゴシックをフォントとして取得し、
Charsetを行わないとArialを取得します。
これらが何のフォントを取得しているのか、追い切れておりません。

以上、たびたび申し訳ありませんが、よろしくおねがいいたします。

[ツリー表示へ]
タイトルRe^8: Windowsのシステムで使用しているフォントの取得。
記事No14295
投稿日: 2009/11/24(Tue) 18:05
投稿者ヨシ
すみません。
追記です。

    lngRet = SystemParametersInfo(31, Len(A), A, 0)
    strResult2 = StrConv(A.lfFaceName, vbUnicode)
    strFin2 = Left(strResult, InStr(strResult2, Chr(0)) - 1)

を行うと日本語OSでは、"Text1.Font.Charset = 128"の実行有無にかかわらず
MS UI Gothicを取得できますが、中国語OSでは、
Text1.Font.Charset = 128を実行済みだと MS P Gothicを取得し、
中国語の表記は文字化けします。
Text1.Font.Charset = 128を実行していないとArialを取得し、
やはり中国語の表記は文字化けします。

たびたび申し訳ありません。
よろしくお願い申し上げます。

[ツリー表示へ]
タイトルRe^9: Windowsのシステムで使用しているフォントの取得。
記事No14296
投稿日: 2009/11/25(Wed) 01:12
投稿者魔界の仮面弁士
> を行うと日本語OSでは、"Text1.Font.Charset = 128"の実行有無にかかわらず
そもそも、Charset プロパティが固定値というのはマズイと思いますよ。

> MS UI Gothicを取得できますが、中国語OSでは、
> Text1.Font.Charset = 128を実行済みだと MS P Gothicを取得し、
> 中国語の表記は文字化けします。
中文版で128を選択した理由は何でしょうか?
http://hanatyan.sakura.ne.jp/vb60bbs/wforum.cgi?no=13332&reno=13328&oya=13326&mode=msgview&page=150

> Text1.Font.Charset = 128を実行していないとArialを取得し、
実行していない時の Charset は何ですか?
0 だとしたら、それは欧文フォントを意味します。

> やはり中国語の表記は文字化けします。
もうひとつ。日本語版であれば、ランタイムに vb6jp.dll が必要であるように、中文版の
実行環境にも、対応するサテライトライブラリが必要ですが、その点は大丈夫ですよね?
(多分、繁体字版ならvb6cht.dll、簡体字版ならvb6chs.dll)

[ツリー表示へ]
タイトルRe^8: Windowsのシステムで使用しているフォントの取得。
記事No14297
投稿日: 2009/11/25(Wed) 02:15
投稿者魔界の仮面弁士
> 下記のようなコードで動作確認をしています。
私は、
>>> コピー & ペーストで検証可能なコードが提示されれば、
と書きましたが、提示されたコードは Declare 等がありませんので、
残念ながら、第三者が検証することはできる物にはなっていないようです。

元のコードをある程度想像することはできますが、ByVal/ByRef の宣言の違いや、
As Any/As Long/As ユーザー定義型 の違いなどで、動作が異なってしまう事も
珍しくないので、API 宣言部まで含めて提示していただいた方が指摘しやすいです。


> Private Const LF_FACESIZE = &H20
> Private Type LOGFONT
中略
>     lfFaceName(LF_FACESIZE)     As Byte
> End Type

Option Base は 0 なのですよね? だとしたら、宣言が間違っていると思います。
元となる WinGDI.h においては、この宣言は
》    CHAR      lfFaceName[LF_FACESIZE];
と定義されています。つまり、32文字分の領域を持つメンバということです。しかし、
ヨシさんが書かれた宣言では、0 To 32 の範囲すなわち 33 バイトの領域になっています。

また、上記の宣言を使おうとしているとことは、現在の Declare 宣言では、
SystemParametersInfoA を用いているのかと想像します。

文字列を扱う API に対して、ANSI 版の実装を利用しようとする場合、VB6 では
Unicode と既定の文字コードとの間で、暗黙の変換作業が入ることになります。
多言語対応にする場合、この時点での破損を防ぐ意味でも、文字コード変換の伴わない
SystemParametersInfoW などの Wide 版 API を用いた方が良いかと思いますよ。

>         dim strResult as string
>         dim lngRet as long
>         dim A as LOGFONT
>         dim i as integer
実際のコードからコピーしてきたものではありませんね?


> strResult = strResult & Chr(A.lfFaceName(I))
多言語対応するのであれば、Chr 関数は避けた方が良いかと。
StrConv を第3引数付きで呼び出すか、もしくは、そもそも ANSI 処理は避け、
すべて Unicode 版 API で制御するようにしてみてください。


>     Text1.Font.Charset = 128
ここで、128 という固定値をセットしているようですが、それは
この段階で、A.lfCharSet の内容も 128 になっていたという事でしょうか。


>     Text1.Font = strResult
Font プロパティに String を渡してはまずいでしょう。

フォント名を渡すなら、
 Text1.Font.Name = strResult
と書くべきですし、Font プロパティにフォントそのものを渡す意図なら、
 Dim F As Font
 Set F = New StdFont
 F.Name = …
 F.Size = …
 F.CharSet = …
  :
 Set Text1.Font = F
のようになるかと。


> A.lfFaceName に格納される値は、バイト型で下記になります。
> 183
> 76
> 63
> 182
> 174
> 182
> 192
合計7バイト、という事ですね。

お使いの中国語の文字コードは何ですか? (Big5 とか GB2312 とか)
また、本来取得されるべき文字列は、何という文字列ですか?

>(おそらく「微軟正K體」)
漢字5文字だとしたら、7バイトしか無いのは間違っていますよね。

微軟正K體だとしたら、
 繁体字中国語(Big-5) :B7,4C,B3,6E,A5,BF,B6,C2,C5,E9
 簡体字中国語(GB2312):CE,A2,DC,9B,D5,FD,BA,DA,F3,77
 Unicode     (UTF-16):AE,5F,DF,8E,63,6B,D1,9E,D4,9A
 日本語   (Shift_JIS):94,F7,93,EE,90,B3,FC,4B,E9,93
と 10 バイトにエンコードされる事でしょう。しかし、提示の7バイトは、
 B7,4C,3F,B6,AE,B6,C0
という事で、上記どれとも一致していませんので、API の扱いに
そもそも問題があるように思えます。宣言にしても、Chr 関数を使っている点にしても。


そもそも 〜A系 API ではなく、〜W系の実装を使えば、そうした変換自体が不要ですが、
もしも 〜A系を使うなら、Byte 配列を String に戻す際には、Chr 関数ではなく、
ADODB.Stream 等を用いるか、StrConv の第3引数指定を利用してみてください。


たとえば下記はいずれも、「微軟正K體」を表すバイナリを文字列に復元しています。
(ToBinary という部分は、Byte 配列を表していると思ってください)


Dim buf() As Byte

'日本語(Shift_JIS)
buf = ToBinary("94,F7,93,EE,90,B3,FC,4B,E9,93")
Debug.Print StrConv(buf, vbUnicode, 1041)


'繁体字中国語(Big-5)
buf = ToBinary("B7,4C,B3,6E,A5,BF,B6,C2,C5,E9")
Debug.Print StrConv(buf, vbUnicode, 1028)


'簡体字中国語(GB2312)
buf = ToBinary("CE,A2,DC,9B,D5,FD,BA,DA,F3,77")
Debug.Print StrConv(buf, vbUnicode, 2052)


'Unicode(UTF-16)
buf = ToBinary("AE,5F,DF,8E,63,6B,D1,9E,D4,9A")
Debug.Print StrConv(buf, 0, 0)

' Vista Business (x64) SP2/ XP Professional (x86) SP3 で動作確認。


なお、StrConv の第3引数に指定した LocaleID が実行環境でサポートされていない場合、
実行時エラーとなります。

[ツリー表示へ]
タイトルRe^9: Windowsのシステムで使用しているフォントの取得。
記事No14298
投稿日: 2009/11/25(Wed) 17:01
投稿者ヨシ
ご丁寧なご対応、恐れ入ります。ありがとうございます。
いただいたアドバイスをもとに中国語OSでシステムフォントを
自動取得して、文字化けせずに表示させることができるようになりました。
使用したのはSystemParametersInfoAです。(WはAPIビューアで検索できませんでした。)
定義はAPIビューアで取得したままです。

Private Declare Function SystemParametersInfo Lib "user32" _
Alias "SystemParametersInfoA" _
(ByVal uAction As Long, _
ByVal uParam As Long, _
ByRef lpvParam As Any, _
ByVal fuWinIni As Long) As Long


Fontに対してString型を入れていたのが最大の問題だったようです。


> フォント名を渡すなら、
>  Text1.Font.Name = strResult
> と書くべきですし、Font プロパティにフォントそのものを渡す意図なら、
>  Dim F As Font
>  Set F = New StdFont
>  F.Name = …
>  F.Size = …
>  F.CharSet = …
>   :
>  Set Text1.Font = F
> のようになるかと。
このご指摘に従った結果、中国語OSでも正常にフォントが設定され、
文字化けしなくなりました。
大変お手数をおかけいたしました。
ご対応ありがとうございました。

[ツリー表示へ]
タイトルRe^10: Windowsのシステムで使用しているフォントの取得。
記事No14300
投稿日: 2009/11/25(Wed) 18:19
投稿者魔界の仮面弁士
> このご指摘に従った結果、中国語OSでも正常にフォントが設定され、
> 文字化けしなくなりました。
“微軟正K體”が 7 バイトだった件や、Charset に 128 がセットされた理由など、
幾つか消化不良な点が残っている気もしますが、まぁ、解決したようで何よりです。


> 使用したのはSystemParametersInfoAです。(WはAPIビューアで検索できませんでした。)
W 系文字列関数の多くが、Win9x 系の OS には実装されていないという事情からでしょう。
(Windows NT 系、2000 や XP 以降の OS のみを対象とする場合は、A/W 両方が使えます)

ちなみに今回は関係ありませんが、Windows CE 環境だと、W 系しかありません。


> 定義はAPIビューアで取得したままです。
APIビューアというよりも、元データとなる Win32api.txt の方ですよね?
(CE 向け開発の場合には、WinCEAPI.txt)

Win32api.txt は何度か更新版が出ていますが、それでも今回のような間違いが
残っています。それに、同じ API 関数に対して複数の Declare 定義が
必要になるケースもありますので、そのまま鵜呑みにしない方が良いですよ。
http://www.int21.co.jp/pcdn/magazine/mado/emg0705/emg0705.html
http://support.microsoft.com/kb/178020/ja

APIビューアを使うのであれば、Win32api.txt (あるいはそこから生成した mdb)を
御自身で鍛えて(編集・追加して)いきながら使うツールだと思った方が無難かと。

[ツリー表示へ]