tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re^9: ファイルパスの機種依存文字を取得する方法について
投稿日: 2014/12/09(Tue) 20:43
投稿者魔界の仮面弁士
> > 描画処理を UserControl 化しておくと、通常の Label の代用として使えるかと。
> Visual Basic Learning Edition Version 5.0ではActiveX コントロールを作成できません。
ActiveX コントロールにする必要は無く、UserControl で十分なのですが、
UserControl の作成も駄目なんでしたっけ? (済みません、把握できていません)


> DrawText内の"s = Text & vbNullChar"はC言語風文字列で宜しいですか(下記ページ参考にしました)?

ひとまず、その認識で OK です。(風、が付いているのがナイス!)

正確には LPCTSTR 型(LPCWSTR 型)相当のデータが渡されますが、
ここでは、NULL 終端文字は必須ではありません。

終端文字は念のためにつけただけですが、それがかえって問題になっていますね。
改めて No16043 のコードを見直してみたのですが、提示コードの
 TextOutW h, x, y, StrPtr(s), Len(s)
というのは誤りでした。NULL 終端を含まない長さを指定するべきなので、この場合は、
 TextOutW h, x, y, StrPtr(s), Len(Text)
もしくは
 TextOutW h, x, y, StrPtr(Text), Len(Text)
が適切です。コードの修正をお願いします。 ( No16043 のコードは修正済みです)



> TextOutWは宣言で全てLong型となっているため、数値で判断して
> 描画を行う事がわかります。
TextOutW API の引数は、以下の意味です。
http://msdn.microsoft.com/en-us/library/windows/desktop/dd145133.aspx


第一引数(HWND) 描画対象となるデバイスコンテキストのハンドルを指定します。
  通常は、描画先コントロールの hDC プロパティを指定することになります。
  (hDC プロパティは、Form、PictureBox、Printer に備わっています)

第二引数(int) X 座標を指定します。ピクセル単位系です。

第三引数(int) Y 座標を指定します。ピクセル単位系です。

第四引数(LPCSTR) Unicode 文字列の先頭アドレスを指定します。
 VB5 から渡す場合は、
  (案1) ByRef As Byte で宣言して、「Byte 型一次元配列」の 0 番目の要素を渡す。
  (案2) ByVal As Long で宣言して、「StrPtr( 文字列型変数 )」を渡す。
 などとします。今回は 案2 ですね。詳しい話は後述。

第五引数(UINT) 第四引数の文字数を指定します。(バイト数ではなく文字数です)



> 関数(DrawText)を使用してTextOutWを実行するのは、数値を取得するためですか?
そもそも、今回のサンプルにある DrawText は『関数』ではありません。
自作 Sub プロシージャーの名前です。

API には DrawText という同名関数もありますが、サンプル中のそれとは
無関係です。紛らわしい名前をつけてしまって済みません。

ちなみに、API としての DrawText 関数は、TextOut 関数の上位バージョン的な位置づけです。
TextOut が、描画先の左上座標を指定して文字列を描画していたのに対し、
DrawText は四角形の領域を指定しての描画となります。下揃え・右寄せ・中央揃えなどの位置調整や
長い文字列を折り返したり、あるいは末尾を切り抜くなどの高度な指定が行えます。



> (StrPtr(s)のs、イミディエイトウィンドウでは数値でした、数値は格納場所の意味?)?
StrPtr は、文字列の先頭アドレスを返すための隠し関数です。

ANSI API の場合は、String 型変数をそのまま渡せるのですが、VB5 でこれを
やってしまうと、Shift_JIS ←→ Unicode の変換が行われてしまいます。

たとえば "弁士" という文字列を、ANSI 系 API に ByVal As String で渡すと、
(Unicode バイナリの) 5F01, 58EB ではなく、
(Shift_JIS 相当の) 95D9, 8E6D が渡される仕様です。

一方、同じ文字列を、Wide 系 API に、StrPtr などで渡す場合は、
(Unicode バイナリの) 5F01, 58EB をそのまま渡すことが出来ます。



文字列型のメモリ配置を図で示すとこんな感じ。画像はネットからの拾い物です。
http://blog-imgs-70.fc2.com/n/a/o/naotamin/VBAString1.png

 黄色:「文字列型変数」を管理する 4 バイトの領域。
  この領域の先頭アドレスは、VarPtr(s) で得られます。
  この場所には、青部の左端のアドレスが記録されています。
  ※ vbNullString の場合は、青部のアドレスのかわりに &H0& が記録されています。

 青色:「文字列の本体」が管理されています。
  この領域の先頭アドレスは、StrPtr(s) で得られます。黄色領域はここを参照しています。

 黄緑:「文字列の長さ」を管理する 4 バイトの領域。内容は LenB(s) と同じものです。

 灰色:NULL 終端文字列。4 バイトの 0 vbNullChar に相当します。

--------

たとえば s = "弁士" なら、
 黄色部のアドレス
 = VarPtr(s) が指し示す数値

 黄色部の値
 = 文字列本体の格納場所を示す
 = すなわち、青色部の先頭アドレス
 = StrPtr(s) が指し示す数値

 青色部の値
 = 文字列本体の内容を示す
 = "弁士" という 2 文字
 = ChrW(&H5F01) & ChrW(&H58EB)
 = ChrB(&H01) & ChrB(&H5F) & ChrB(&HEB) & ChrB(&H58)
 = 青色部の値は [01][5F][EB][58] の 4 バイト

 黄緑部のアドレス
 = 青色部の直前に配置される(4 バイト)

 灰色部のアドレス
 = 青色部の直後に配置される(4 バイト)

 黄緑部の値
 = 青色部のデータ長を示す
 = LenB(s) が指し示す値

 灰色部の値
 = [00][00] 固定

というわけです。


> DrawText(Call DrawText)後のPictureBoxのRefreshは、
> 実行しなくても表示できました。
AutoRedraw = False の場合は、Refresh 無しでも描画されます。
その代わり、再描画時には消えてしまうため、AutoRedraw = False 時は、
描画処理を「Private Sub Picture1_Paint()」内で行う必要があります。

一方、AutoRedraw = True の場合は、自動再描画が行われます。
たとえば Form_Load 内で描画しておいた場合には、Refresh は不要です。
そもそも描画が発生するタイミングと言うのは、たとえば
 ・自コントロールの Refresh メソッドを呼び出したとき
 ・親コントロールの Refresh メソッドを呼び出したとき
 ・自コントロールのサイズが変更したとき
 ・自コントロールの Visible プロパティが変更されたとき
 ・上に別のウィンドウが被さっていて、それが取り除かれたとき
などです。何らかの描画タイミングがあれば、Refresh 以外の要因でも
描画されますが、それが不定な場合は Refresh で強制再描画させます。


> ReplaceはVB5.0にはありませんでした。
そういえばそうでしたたね。それに Split も。

VB5 での代替コードはこちら。
http://support.microsoft.com/kb/188007/ja


> TextOutW関数で、.lpstrFileのプロパティが数値で表示されるため、
> 型をString型に変更して上記のコードで実行すると、パス名を表示できました。

それは、TextOutA を使う場合のやり方です。TextOutW では String にしてはいけません。

String 型を使うと、自動的に Shift_JIS 変換されてから受け渡されますので、
それを避けるため、String 型ではなく、そのアドレスを渡しているというわけです。
(これが VB.NET なら、String を ANSI/Wide いずれで受け渡すのかを指定できるのですけれどね)


> 引数TextにStrConvでUnicodeから変換して格納しました。
その方法でうまく渡せた文字があったとしても、それはただの偶然です。

そもそも、StrConv した時点で破損していませんか?


たとえば vbFromUnicode 変換の場合:

Dim S As String
Dim bin() As Byte

S = ChrW(&H33A5)            '立方メートル
Debug.Print Hex(AscW(S))    '33A5 なら成功

bin = StrConv(S, vbFromUnicode)     'Unicode バイナリを「Unicode→Shift_JIS変換」
Debug.Print Hex(bin(0))     'Shift_JIS に無い文字なので「?」などに化ける


ChrW(&H33A5) ではなく、Shift_JIS にある文字なら、VB 内では破損しませんが、
それを API に String で渡すと「Shift_JIS バイナリを、Unicode→Shift_JIS 変換して渡す」という
謝った処置が行われるので、どちらにせよ破損することになります。



もしも vbUnicode だとしたら、「Unicode バイナリを、Shift_JIS→Unicode変換」して壊してから、
それを API に渡して「壊れたバイナリを、Unicode→Shift_JIS変換」してさらに壊すという流れです。
中には、偶然元に戻る文字もあるかも知れませんが、意図した処理では無いですよね。


> Shell関数で
Shell 関数は、NT系列の OS 上で動かす場合に限り、Unicode 文字を扱えたと思います。
手元に検証環境が無いのでうろ覚えですが。


> VB2005はフリーのVisual Basic 2005 Express Edition をダウンロードして
> 所持しているという意味でした。
今なら、Visual Studio Community 2013 の方が良いでしょう。
個人利用なら無償で利用できる上に、機能制限もありません。
http://www.microsoft.com/ja-jp/dev/products/community.aspx

業務利用の場合は、Visual Studio Express 2013 ですかね。
機能制限はありますが、こちらも無償です。


なお、2012 や 2013 のバージョンは、Windows XP や Windows Vista では利用できません。
Vista までの古い OS を使っている場合には、2010 以下のバージョンをご利用下さい。


> VB2005で慣れてからでないと最新版をインストールしないと思います。
VB5 は、複数のバージョン(VB4 や VB6)とは同居させられませんでしたよね。
http://support.microsoft.com/kb/412579/ja

しかし、VB2005 と VB2008 以降については同居可能です。
というよりも、VB5(または VB6)から VB.NET への移行組ならば、
VB2005(または VB2008)も入れておいた方が良いでしょう。
VB2010 以降では「VB6 コードの変換機能」が廃止されていますので…。


> VB5.0を希望しているのは、作成している自作プログラムがVB5.0の勉強のために
> 作成したもので、言語を換えたくない気持ちがあるためです。
VB5 が登場したのは 17 年前ですね。

発売したばかりの新車より、17年前の中古車が好きな人も居るわけですから、
新しい言語の学習コストと、古い設計ゆえに発生する手間を比較した上で、
その上で VB5 の方に価値があると判断されるのであれば、それは個人の判断でしょね。
(自分も、未だに VB6 をちょくちょく併用しています)


ですから、今回のプログラムを今のまま修正できそうであれば、あえて新言語で
書きなおしたりはせず、VB5 を使い続けるというのも、一つの選択肢だと思います。

しかし、もしも『勉強』を主目的としているのであれば、現行バージョンを学ぶべきかと。



そもそも、Visual Basic 5.0 の対応 OS は、Windows 95、Windows 98 までとなっています。
NT 系は 3.51 Workstation まで(Server 版は非対応)なので、幾らなんでも古すぎますね。
Windows Me、NT4、2000、XP 等はサポート対象外であり、現行 OS は言わずもがな。

開発環境ではなく、実行環境としての利用に限るのであれば、後継 OS であっても
VB5 製アプリが運良く動作する可能性は高いです。
(未だに VB2 を動かしている現場もあったりするぐらいですし)

とはいえ、VB5 向けの情報はネット上でもどんどん失われている状況ですし、
今回の問題以外にもいろいろと問題をかかえています。
(たとえば、ライセンス上の問題により、現行 OS 上では、
セットアップウィザードによるインストーラー作成が行えないなど)

古い環境をどうしても生かさねばならない事情があるのならば已むを得ませんが、
新しい情報が入ってこない以上、発生する問題を自力で解決する能力が求められるので、
難易度はむしろ高くなる可能性があることは覚悟しておいた方が良いと思いますよ。


なお、今から移行するつもりなのであれば、VB2005 は少々古いように思えます。
せっかく覚えても、慣れたころににはまた陳腐化してしまうというのでは勿体無い…。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。