「覚え間違い」を教えてください!

よろしくお願いします。
VB6.0sp6,Windows2000professionalsp4です。
VBでのディレクトリの有無の判別方法を検索していて、サンプルをひとつ見つけたのですが・・・↓がコードです。
------------------------------------------------
Private Declare Function PathIsDirectory Lib "SHLWAPI.DLL" Alias "PathIsDirectoryA" _
(ByVal pszPath As String) As Long
'
' ディレクトリであるかどうか
'
Private Function IsDirectory(ByVal strFileName As String) As Boolean
' strFilename : チェックしたいディレクトリ名
' 戻り値 : ディレクトリであればTrueを返す。

Dim lngResult As Long
lngResult = PathIsDirectory(strFileName)
IsDirectory = Not (lngResult = 0) 'ここが理解できません
End Function

Private Sub Command1_Click()
Dim strFileName As String
strFileName = "C:\WINNT\Profiles\Administrator\My Documents\HEROPA\TestCls\SHLWAPI"
Msgbox IsDirectory(strFileName)
End Sub
--------------------------------------------
IsDirectory関数は、PathIsDirectoryの戻り値がLong型のため、それをBooleanに直すためのものだと思うのですが、
IsDirectory = Not (lngResult = 0)はどういう原理なのでしょうか?
これだとlngResultにどんな値が入ろうがIsDirectoryに返されるのはTrueになってしまうと思うのですが(lngResultに0が代入され、それがNotされるから)、しかし実際に実行してみるとちゃんとTrueとFalseを判定しています。いったいどうしてなのでしょうか?

それと、PathIsDirectoryの宣言で、関数の戻り値がLongになっていますが、他に見つけたサンプルではBooleanとなっていました。どちらが正しいのでしょうか?

A 回答 (9件)

>VBでのTrueは-1という理解でいいのでしょうか?それとも0以外という理解が正しいのでしょうか?


値としては、-1です。

ただ、Trueを固定値概念で持つ必要はありません。
False(0)でなければ、Trueの分岐部が走ります。
だから「VBでのTrueは」というより「VBでのTrue値は」であれば、確かに-1です^^;

そういう認識を持っていれば、言語を意識しないで済むと思いますよー


最初の発言に戻りますが、
>PathIsDirectoryの宣言で、関数の戻り値がLongになっていますが、他に見つけたサンプルではBooleanとなっていました。どちらが正しいのでしょうか?
PathIsDirectory自体は、DLLに用意されれある関数ですよね?
自分で作成したものではなく、既に用意されているDLLの関数を、どのように利用するかというのがAPIの宣言です。


他の例ですが(ちょっと例えが悪いかもしれませんが)、
Declare Function API関数 Lib "HOGEHOGE.DLL" (ByRef パラメータ As 構造体) As Long
と切る場合もあれば
Declare Function API関数 Lib "HOGEHOGE.DLL" (ByVal パラメータ As Long) As Long
と切るパターンもあります


結果としては、どっちでもいいです。
この例のAPI関数においてはパラメータ部で、構造体の先頭ポインタさえ渡れば、どっちでもいいわけです。
この関数を利用する人の利用したいように宣言ができます。


戻り値部分にいたっては、もっと融通が利きます。
Cに渡す部分であれば、DLLが欲しているパラメータなので、ある程度の制約が発生しますが、戻り値はこっちが受ける部分なので、DLLがその戻り値に対し、メモリを参照することはありません。



私の持っているMSDNでは
BOOL PathIsDirectory(
  LPCTSTR pszPath
  );
と書いてあるので、2つの固定値を返す関数のようですね。
さらに0と16を返すようです。

16が返るからといって、わざわざこれをLongで受けて、
If (Long戻り値=16) Then
なんてやる人はいませんよね^^;
そこでキャストして受けるようにしてあげれば、Longの概念が打ち消せるわけです。

ちなみにCで利用するパターン(参考までにです)
http://nienie.com/~masapico/api_PathIsDirectory. …


(確か海外のVBのサイトだったと思うけど)Win32APIタイプライブラリというのが存在しています。
それを参照すると、APIの宣言をしなくてもよいという代物です。
そのタイプライブラリはAPIビューワと、結構違います^^;
APIビューワだけが正ではありません。


たくさんAPI利用のサイトを見たらわかると思いますが、みんな結構バラバラですよね^^;
私に限らず、結構オリジナルでやる人が、今では多いと思いますよー
IN/OUT/戻り値を意識していれば、正しいパターンは複数あります。
計算ドリルと違って、正解は一つじゃないのです。

結果、PathIsDirectoryの戻りは、BooleanであろうとLongであろうと、間違いはありません。
どういう宣言が、一番目的に適しているかで、自分で扱いやすい方を選択したらいいと思いますよ。
    • good
    • 0
この回答へのお礼

ほぼ理解できました。何度も回答していただき本当にありがとうございます!
ところで、最近のプログラミング雑誌には、VB6.0の記事はほぼ見られなくなりました。.netを購入する財布も、気力もない私としてはつらいです。6.0もまだまともに使えないのに.netに移ってもしかたありませんしね。
思えばこれまでいろいろな言語を、つついては放り、放ってはつつきとなんだかうじうじやってきました。結果、あまりにも自分の持つ知識が使い物にならないかを実感する毎日です。
もっとがんばらねば、と思いました。
どうもありがとうございました!

お礼日時:2005/03/20 17:20

>>>C/C++やAPI関数の戻り値では基本的に「False=0」「True=0以外」です。


>>とありますが、VBでも一緒です。

>VBは違いますよ(^^;

例えばですが
If 9999 Then
  MsgBox "True 処理"
Else
  MsgBox "False 処理"
End If

とすると、TRUE処理が走ります
9999に限らず0以外ならTRUE処理となります。


>確かに、CBool()ではゼロ以外をTrueと判定してくれますが、
>試しにイミディエイトウインドウで
>?Cint(true)
>?Clng(True)
>としてみてください。
>この場合のイコールは「一対一」という意味です。
それを言うと、キリがないのですが、
CではTrueをintにキャストしたら、1なのですが。。。

CやVBに限らず、[FALSE=0] というのは、私の知る限りでは「プログラミング言語」全体的にそうなのではないでしょうか?
Trueを判定するより、Falseを判定する方が処理ステップが少なく済む場合が多いです。(直近の業務がアセンブラだったので^^;)
簡素な言語レベルでそうなので、その上をいく近代言語でも、基本的なルールは変わらないと思います。

上記例でも
If 9999 Then
の中では
[9999]は[0]ではないから
という処理が予想できます。

if (9999) {
  MessageBox (0,"true処理","",MB_OK);
} else {
  MessageBox (0,"false処理","",MB_OK);
}
これはCでも一緒ですよね^^;



さらに別例も揚げておきます。

Cでの永久ループ
while (《0以外の整数値》) {
};

VBでの永久ループ
Do While (《0以外の整数値》)
Loop



>これを「気持ち悪い(Boolean型への暗黙のキャストなので)」と取るか、「使えればOK」と取るかはその人次第なのかもしれませんが、私個人としては「基本をきっちり押さえること」が大事だと思ってます。
はい、それは非常にわかります。私も当初は「暗黙のキャスト」は非常に疑問を覚えました。
しかしそれを利用する事で、ステップ数の削減を行えるので、VBの利点として逆手に取ることもできます。

>ですから、「誉められない」と書いたのです。
もう、これは価値観かな^^;
    • good
    • 0
この回答へのお礼

>Trueを判定するより、Falseを判定する方が処理ステップが少なく済む場合が多いです

貴重な情報をありがとうございます。脳に刻みました。

すみません。混乱してきました。VBでのTrueは-1という理解でいいのでしょうか?それとも0以外という理解が正しいのでしょうか?

お礼日時:2005/03/20 01:22

#6さんは、結構お出来になる方みたいですね(^^;



>私も、宣言はオリジナルでやっちゃいます。

私も、個人で作っているプログラム(で、かつソースを公開しない)ならそうすると思います。
ただ、仕事で使ったり他の人にソースを流用される可能性がある場合は、少なくともコメントは入れると思います。

実際に、tochanxさんが「なぜここはBooleanなのだろう」と疑問をもたれてますよね。これは可読性を失った結果・・・だと思うのです。

>>C/C++やAPI関数の戻り値では基本的に「False=0」「True=0以外」です。
>とありますが、VBでも一緒です。

VBは違いますよ(^^;

確かに、CBool()ではゼロ以外をTrueと判定してくれますが、
試しにイミディエイトウインドウで
?Cint(true)
?Clng(True)
としてみてください。
この場合のイコールは「一対一」という意味です。

MS-Basicで良く、論理式でTrueの場合は-1を返すということを利用して
i = (k > 0)*(-20) + 80
みたいな式を書いたことがある人は、BasicでのTrue(真)は-1ということを良く知っているんですけどね(^^;
# もっとも、今こんな式を書いたら怒られてしまいますけど(^^;

前に戻って、もしPathIsDirectoryが「0か-1か」を返す関数であればBooleanで全く問題ないですね。
# BOOLなので0か1か、かもしれませんけど

ですが実際に(Longで宣言した上で)
debug.print PathIsDirectory("C:\")
としてみてください。
# 私の環境では16が出力されました

これを「気持ち悪い(Boolean型への暗黙のキャストなので)」と取るか、「使えればOK」と取るかはその人次第なのかもしれませんが、私個人としては「基本をきっちり押さえること」が大事だと思ってます。
ですから、「誉められない」と書いたのです。

ちょっとキツイ内容になってしまいましたが、私も敵意があるわけではないのでご容赦を(^^;
    • good
    • 0
この回答へのお礼

お礼が遅れてしまい申し訳ありません。
なるほど!理解が少し深まりました。ありがとうござます!

確かにCint(true),Clng(true)の結果はともに-1になりますね。VBではTrueは-1ということですね。

すみません。ちょっとわからないのですが、

>この場合のイコールは「一対一」という意味です

というのはどういう意味なのでしょうか?

私の環境でも16が出力されました。

お礼日時:2005/03/20 01:17

#5さんに一部賛同で一部反論(敵意ではないのでご容赦を)




>PathIsDirectoryの宣言で、関数の戻り値がLongになっていますが、他に見つけたサンプルではBooleanとなっていました。
>どちらが正しいのでしょうか?
まず、どちらが正しいという考えはありません。
APIの宣言は、関数ではなく「宣言」です。
それよりLongかBooleanかを問いてますが、その部分は返し値部分なので、

「返す値の範囲を理解する事」
「どのような利用の仕方をするか」
というのが大事だと思います。

APIにまだ不慣れなら、#5さんが述べられているような方法をお勧めいたします。
でも慣れたら、教科書通りのやり方をする必要はありません。私も、宣言はオリジナルでやっちゃいます。
ただ、ここの掲示板で書くときは、APIビューワの宣言から利用します。
#5さんの発言どおり、掲示板なので
>可読性
を重視した内容にするためです。


突然ですが、APIサンプルの超有名なURL
vbvbvb.com
http://www.vbvbvb.com/
ぱぱんぶいびぃ
http://www.mitene.or.jp/~sugisita/
Visual Basic Station
http://www1.harenet.ne.jp/~unaap/

かなりヘビーなAPI使い師です。
各サンプルは、パラメータであればほとんど一緒ですが、戻り値にいたっては宣言方法がみんな一緒とは限りません。

またvbvbvb.com運営者とぱぱんぶいびぃ運営者が登録しているVBのメーリングリストが存在しています。
これまたヘビーなメーリングリストで、回答がC++で返ってくることもあるようなところです。

そこでも、戻り値の型を意識するより、APIの特性に意識するように結論が出ていました。
要は「せっかくのVBなんだから、使えればOK」って感じだと思います。
パラメータではないので、PathIsDirectoryの戻り値の取る範囲から、メモリリークを意識しないでもいい事は明らかです。


あと#5さんへの補足
>また#2さんが指摘されていらっしゃるように
>VBでは「True=-1」「False=0」なわけですが
>C/C++やAPI関数の戻り値では基本的に「False=0」「True=0以外」です。
とありますが、VBでも一緒です。

#2さんが
>しかし、実際には
>Not 0→True
と言っている部分があります。その部分のことですね。
vbvbvb.com のサンプルの多くは、これを意識したAPI関数の利用になっていると思います。
    • good
    • 0
この回答へのお礼

お礼が遅れて申し訳ありません。
どうもありがとうございます!
非常に勉強になります。教科書に書いていないことばかりで、とてもわくわくします。
リンクまでたくさん提示していただき、本当に助かります。
vbvbvb.comには以前いったことがあるのですが、挫折してしまいました・・・


すみません。一ヶ所理解できないところがあります。もしよろしければ補足をお願いしたいです。

>パラメータではないので、PathIsDirectoryの戻り値の取る範囲から、メモリリークを意識しないでもいい事は明らかです。

ここが理解できません。戻り値の取る範囲から、メモリリークを意識する必要がないとはどういうことなのでしょうか?

回答ありがとうございました!

お礼日時:2005/03/20 01:08

>どちらが正しいのでしょうか?



#1さんが#3で指摘されておられるように「Long」です。
というより、API関数の殆どの戻り値はHANDLEにしろポインタにしろ(VB内部では)Longで帰ってきます。

>他に見つけたサンプルではBooleanとなっていました。

は、単にこのケースで言うと「Declare宣言だけでIsDirectoryと同じ事を実現する」為だと思います。
手抜きといっては手抜きですが、こういうのはあまり誉められませんね(^^;

まあ、イミディエイトウインドウで
?CBool(1)
?Cbool(0)
とでもしてみれば分かると思いますが、この関数に関しては0なら失敗、それ以外なら成功なので実害はありませんけど。

また#2さんが指摘されていらっしゃるように
VBでは「True=-1」「False=0」なわけですが
C/C++やAPI関数の戻り値では基本的に「False=0」「True=0以外」です。
IsDirectory = Not (lngResult = 0)
という表現は、これを意識してのことだと思いますよ(^^;
# C/C++で良く
# if (!hoge()){...
# と書くのと一緒かと。

#1さんが「Boolean型のサイズが変わるかもという話」をされていますが、これはC/C++では考慮しないといけない話ではありますが、VB6ということであれば考える必要は全くありませんね。
そもそも64BitプラットフォームではVB6なんて使えないでしょうし・・・(^^;

>計算量が少なくて効率的な気がするのですが

現在のコーディングでは、効率より可読性を大事にするケースのほうが多いと思いますし、そうすべきだと思います。

(lngResult <> False)
では、もしlngResultがBooleanだったらそんな書き方はせずに
(lngResult)
または
(lngResult = True)
と書きますよね。
それに、そもそもlngResultはLong、True/FalseはBooleanですから、違う型で比較するのは直感的に嫌な感じがします(^^;
    • good
    • 0
この回答へのお礼

どうもありがとうござます!
?は自動的にPrintに変換されるんですね!
大変示唆に富んだ内容で、とても勉強になりました!

お礼日時:2005/03/14 22:49

「<>」


私もそうなのですが、一部の人が嫌います。

これはおそらく、他の言語ではあまり見かけないからじゃないかなー

Cやオラクルのストアドプロシージャでは
!(A=B)
と書いて同じ意味を持ちます。

IsDirectoryはAPIを内部で利用しているだけのオリジナル関数だから、返しの型は結局何でもいいです。
ただIsDirectory関数の特性として
・ある
・ない
を返すだけなので、Boolean特性にしているのでしょう。


また、
Not (lngResult = 0)
この表現はよく用いられる書き方です。

APIの定数で
API_FALSE = 0
です。


API関数の戻り値のパターンをあげておきます
(1)存在チェック系など
・[0]存在しない
・[-1]存在する

(2)実行系など1
・[0]失敗
・[正値]成功(1以上の長整数)

(3)実行系など2
・[負値]失敗(エラー番号)
・[正値]成功(1以上の長整数)

(4)実行系など3
・[正値]失敗(1以上の長整数で特定のエラー番号)
・[正値]成功(1以上の長整数で特定の正常ステータス値)

などなど、いっぱいあります。

(1)のパターンのAPIであれば、全て
Not (lngResult = 0)
でステータスを、わかりやすいBoolean型に置き換えることが可能です。
    • good
    • 0
この回答へのお礼

慣習なんですね。勉強になります。
わざわざAPI戻り値のパターンまで教えていただき、ありがとうございます!

お礼日時:2005/03/14 22:38

>プログラミング的にはVBにおけるPathIsDirectoryの宣言では、戻り値の型はBooleanにする方がよいというのは…


すみません、ちょっと調べてみたのですが、
VB6での
Boolean型は、サイズが2バイトで
Long型は、4バイト
SHLWAPI.DLLでの戻り値
BOOL型は、4バイトですので、
型を合わせるということで言えば、Long型の方がいいですね。ごめんなさい。

>Booleanが将来的に他の型を使われる可能性
紛らわしい表現だったかもしれません。
他の型というのは、Boolean型のサイズが変わるかもという話です。(よく考えてみればLong型にしても同じことが言えますね^^;)
Boolean型は、VB6では、前述したように、2バイトサイズですけど、将来的に、(例えば64ビットマシンが基本的なコンピュータとなった時に?、)4バイトになったりあるいは、1バイトになったりする可能性があります。なので、そうした物理的なサイズを指定するより、抽象的な型名を使う方が良いというような意味でした。(今回の質問の場合逆になってしまいました(;^_^A )
ちなみに、VCでは、
BOOL型はint(4バイト)で
BOOLEAN型は、char(1バイト)になっていました。
    • good
    • 0
この回答へのお礼

なるほど、理解できました。
懇切に解説して頂き感謝の極みです。
まことにありがとうございました!

お礼日時:2005/03/14 16:42

0→False


です
-1→True
です

しかし、実際には
Not0→True
です

Not (lngResult = 0)

Not (lngResult = False)

(lngResult <> False)
という意味です。
    • good
    • 0
この回答へのお礼

ありがとうござます。
しかしどうして、
Not (lngResult = 0)

(lngResult <> False)
が同じ式なのにNotの方を採用しているのでしょうか?
Not (lngResult = 0)

(lngResult <> False)
なら、
(lngResult <> False)
の方が計算量が少なくて効率的な気がするのですが・・・

お礼日時:2005/03/14 16:44

VB言語では、


lngResult = 0
は、位置によって代入の場合と論理式の場合があります。
質問文の場合、論理式として評価されます。
なので、代入されるのではなく、0かどうかを調べて、true か falseになります。
IF文で0かどうか調べるときXXX = 0と条件の部分にかきますよね、それと同じです。

>PathIsDirectoryの宣言で、…
APIの説明を観るとBOOL型となっていました。
結局BOOL型の実体がLONG(VBでの)ということなのでしょう
同じコト(最終的に同じものになる場合)でも、
プログラミング的には、Booleanの方がいいのだと思います。(Booleanが将来的に他の型を使われる可能性がありますから)
    • good
    • 0
この回答へのお礼

ありがとうございます。
位置によって論理式として評価されるのですか!なるほど!納得です。

ですが、BLUEPIXY様の回答の後半部分が理解できません。

プログラミング的にはVBにおけるPathIsDirectoryの宣言では、戻り値の型はBooleanにする方がよいというのはわかりましたが、()の中の「Booleanが将来的に他の型を使われる可能性がありますから」というのがわかりません。
よろしければもう少しわかりやすく教えていただけないでしょうか?ヒントだけでもお願いします。

お礼日時:2005/03/14 02:01

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報