tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルVolumeDeviceClassで「〜バッファが無効です」エラー
記事No11417
投稿日: 2015/05/13(Wed) 22:24
投稿者Kobaちゃん
Win7、VB2008Expressで下記のようにVolumeDeviceClassを使ってUSBを外す処理
を実装していますが、なぜか特定のPCで「〜バッファが無効です」のエラーが出ます。
原因と対処方法をどなたか教授お願いしたい。

Public Function Eject(ByVal UsbDrv As String) As String
      Dim res as string
      Dim volumeDeviceClass As New VolumeDeviceClass()
            ↑
   この時点でVolumeDeviceClass.Devices=要求された操作に対して与えられた
      バッファが無効ですとなっている

      For Each device As Volume In volumeDeviceClass.Devices
         ↑ 「〜バッファが無効です」エラーが発生
        If device.LogicalDrive = UsbDrv Then
            res = device.Eject(False)        'OKはNull文字、エラーはエラー内容を返す
            if res=Nothing then
                 Eject="OK"
                 Exit Function
            Else
                 Eject=res
                 Exit Function
            End If
        End If
      Next

[ツリー表示へ]
タイトルRe: VolumeDeviceClassで「〜バッファが無効です」エラー
記事No11420
投稿日: 2015/05/14(Thu) 13:42
投稿者魔界の仮面弁士
.NET Framework に、VolumeDeviceClass というクラスは用意されていなかったように
思うのですが、それは自作されたクラスなのでしょうか?
(Simon Mourierさんの UsbEject Library のことかな…)


> Dim res as string
As や string が小文字になっているところをみると、
実際のコードの一部を切り出したというよりは、
掲示板投稿用に小改修したもののようですね。


>       Dim volumeDeviceClass As New VolumeDeviceClass()
>             ↑
>    この時点でVolumeDeviceClass.Devices=要求された操作に対して与えられた
>       バッファが無効ですとなっている

それは ERROR_INVALID_USER_BUFFER というエラーですね。
.NET のものというよりも、Windows API が用いるエラーメッセージであり、
VB から意図的に発生させる場合には、
  Throw New System.ComponentModel.Win32Exception(1784)
のようなコードを使います。


さしあたり、VolumeDeviceClass のクラス宣言を見せて下さい。
(自作したものでは無いのなら、アセンブリの入手先や名前空間を教えてください)

コンストラクタの呼び出し時(すなわち New した段階)でのエラーではなく、
Devices というメンバー(フィールド? Function? Property?)へのアクセスで
失敗しているのなら、そこに至るまでの部分に問題がありそうです。


> if res=Nothing then
Nothing は = 演算子ではなく、Is 演算子もしくや IsNot 演算子でチェックしてください。

たとえば
 Dim s1 As String = ""
 Dim s2 As String = Nothing
 Dim i3 As Integer? = 0
 Dim i4 As Integer? = Nothing
があった場合、Nothing なのは s2 と i4 ですよね。
その 2 つを正しく判断するには、
 If x Is Nothing Then
の構文が必要となります。もしも
 If x = Nothing Then
の構文にしてしまうと、s1、s2、i3 がヒットし、i4 は Else 句に行ってしまいます。

[ツリー表示へ]
タイトルRe^2: VolumeDeviceClassで「〜バッファが無効です」エラー
記事No11421
投稿日: 2015/05/14(Thu) 21:27
投稿者Kobaちゃん
ご推測の通りSimon MourierさんのUsbEject.Libraryを使わせて頂いています。
掲示板用に修正して短くしましたが実際のコードは下記のとおりです。
よろしくお願いします。
※Nothingの判定はNull文字が返ってくるので、vbNullに変えます。
アドバイスありがとうございます。

Imports System.Management
   ・
   ・
Imports UsbEject.Library

Module EjectUsb

   ・
   ・

    Public Function Eject(ByVal VenNam As String, ByVal SN As String) As String
        Dim volumeDeviceClass As New VolumeDeviceClass()
        Dim DrvNam As String = ""
        Dim ChkMsg As String = ""
        Dim Res As String

        Res = SetDrvNam(VenNam, SN, DrvNam) <- 挿入しているUSBのベンダ名とSNからドライブレターDrvNamを取得
        If Res <> "OK" Then
            Eject = Res
            Exit Function
        End If

        For Each device As Volume In volumeDeviceClass.Devices
            Application.DoEvents()
            If device.LogicalDrive = DrvNam Then
                ChkMsg = device.Eject(False)        'OKはNull文字、エラーはエラー内容を返す
                If ChkMsg = Nothing Then <- ここはChkMsg = vbNullに変えます。
                    ChkMsg = "OK"                   'OKの場合は、OKに置き換える
                End If
                Exit For
            End If
        Next
        If ChkMsg = "" Then
            ChkMsg = DrvNam & " isn't in this PC"
        End If

        Eject = ChkMsg

    End Function

   ・
   ・

End Module

※3年前に周りのPCはXpが主流で、Win7がまだ数台しかなかったころにXp/Win7
で確認していました。昨日久々動かしたのですが、当然のことながら周りのPC
はWin7に全て切り替わっており(Win8はまだ未導入)特定のPCでエラーが出
ました。


> .NET Framework に、VolumeDeviceClass というクラスは用意されていなかったように
> 思うのですが、それは自作されたクラスなのでしょうか?
> (Simon Mourierさんの UsbEject Library のことかな…)
>
>
> > Dim res as string
> As や string が小文字になっているところをみると、
> 実際のコードの一部を切り出したというよりは、
> 掲示板投稿用に小改修したもののようですね。
>
>
> >       Dim volumeDeviceClass As New VolumeDeviceClass()
> >             ↑
> >    この時点でVolumeDeviceClass.Devices=要求された操作に対して与えられた
> >       バッファが無効ですとなっている
>
> それは ERROR_INVALID_USER_BUFFER というエラーですね。
> .NET のものというよりも、Windows API が用いるエラーメッセージであり、
> VB から意図的に発生させる場合には、
>   Throw New System.ComponentModel.Win32Exception(1784)
> のようなコードを使います。
>
>
> さしあたり、VolumeDeviceClass のクラス宣言を見せて下さい。
> (自作したものでは無いのなら、アセンブリの入手先や名前空間を教えてください)
>
> コンストラクタの呼び出し時(すなわち New した段階)でのエラーではなく、
> Devices というメンバー(フィールド? Function? Property?)へのアクセスで
> 失敗しているのなら、そこに至るまでの部分に問題がありそうです。
>
>
> > if res=Nothing then
> Nothing は = 演算子ではなく、Is 演算子もしくや IsNot 演算子でチェックしてください。
>
> たとえば
>  Dim s1 As String = ""
>  Dim s2 As String = Nothing
>  Dim i3 As Integer? = 0
>  Dim i4 As Integer? = Nothing
> があった場合、Nothing なのは s2 と i4 ですよね。
> その 2 つを正しく判断するには、
>  If x Is Nothing Then
> の構文が必要となります。もしも
>  If x = Nothing Then
> の構文にしてしまうと、s1、s2、i3 がヒットし、i4 は Else 句に行ってしまいます。

[ツリー表示へ]
タイトルRe^3: VolumeDeviceClassで「〜バッファが無効です」エラー
記事No11422
投稿日: 2015/05/15(Fri) 10:40
投稿者魔界の仮面弁士
> ご推測の通りSimon MourierさんのUsbEject.Libraryを使わせて頂いています。
存在は知っていますが、使った事は無かったりします。
それゆえ、ライブラリ固有の問題となると回答できる内容を持ち合わせていません。


> ※Nothingの判定はNull文字が返ってくるので、vbNullに変えます。

それはもっとマズイです。

vbNull は VarType 関数の戻り値を判断するために使われる
列挙型であり、この場面でつかうようなものではありません。
ちなみに、CInt(vbNull) は「1」という値を返します。

それが「文字」というのであれば、比較するべきは
vbNull や DBNull などではなく、
Nothing / vbNullString / vbNullChar / "" などでしょう。
(それぞれの違いは分かりますか?)


> Imports System.Management
今回、System.Management 名前空間のクラスも利用されているのでしょうか。
WMI を使う場合、呼び出す機能によっては、追加のアクセス権が
必要になることもあります。(サービスが起動している必要もある)

アプリケーションを「管理者権限で実行」してみて、動作が変わるかどうかも確認してみて下さい。


> Res = SetDrvNam(VenNam, SN, DrvNam) <- 挿入しているUSBのベンダ名とSNからドライブレターDrvNamを取得
Res は Response
Ven は Vendor
Drv は Drive
Nam は…なんでしょう、Name?


SetDrvNam というのは自作関数でしょうか。

DrvNam を更新するのが目的なら、ByRef 引数を使うのではなく、
 DrvNam = GetDrvNam(VenNam, SN)
という実装の方が、コードの意図がわかりやすいかと思います。



> 実際のコードは下記のとおりです。
> よろしくお願いします。
エラー箇所はどこでしょうか?

先の投稿と合わせると、発生箇所とおぼしきは:
 (1) 「New VolumeDeviceClass()」によるインスタンス生成
 (2) 「volumeDeviceClass.Devices」によるコレクション取得
 (3) 「For Each device As Volume」でのコレクション列挙
あたりでしょうか。
現在、2 と 3 は同一行になっているので、コレクションを一度変数に受けるなどして、
どちらの問題であるか切り分けてみて下さい。


また、エラー発生時に、その例外の StackTrace の内容も精査してみてください。

[ツリー表示へ]
タイトルRe^4: VolumeDeviceClassで「〜バッファが無効です」エラー
記事No11423
投稿日: 2015/05/15(Fri) 21:06
投稿者Kobaちゃん
> それゆえ、ライブラリ固有の問題となると回答できる内容を持ち合わせていません。
エラーの原因らしきものが判りました。

問題のPCはWin7ですが、64bit版でした。UsbEject.exe単独で実行してもWindowsエラー
がでて停止しました。UsbEject.exeは対応していないのかもしれません。
単体でも動作しないのでWin7(64bit)での動作はあきらめます。
この質問は一旦ここで解決とさせて頂きます。

ただ、別件ですがこの自作ソフト(USBをドライブ指定して外す)には問題がもう一つあり
ました。

32bit版のWin7では「〜バッファが無効です」エラーが出ないもののUSBを外せません。
UsbEject.exeが何かエラーを出しているのかもしれません。コードを調べてみます。
VB2008Express開発環境が入っているWin7(32bit版)では正常に動作しました。

3年前に作ったときは動作していたはずですが。。。

今、手元に問題のPCがないので来週明けに確認します。
このエラーが自己解決できなければ別のタイトルで質問させて頂きます。


> Nothing / vbNullString / vbNullChar / "" などでしょう。
> (それぞれの違いは分かりますか?)
ネットで調べてみます。


> > Imports System.Management
> 今回、System.Management 名前空間のクラスも利用されているのでしょうか。
> WMI を使う場合、呼び出す機能によっては、追加のアクセス権が
> 必要になることもあります。(サービスが起動している必要もある)
USBのPID、VID、SNを調べるために使っています。


> アプリケーションを「管理者権限で実行」してみて、動作が変わるかどうかも確認してみて下さい。
状況は変わりませんでした。

> Nam は…なんでしょう、Name?
はい、Drive Nameの省略です

> DrvNam を更新するのが目的なら、ByRef 引数を使うのではなく、
>  DrvNam = GetDrvNam(VenNam, SN)
> という実装の方が、コードの意図がわかりやすいかと思います。
SetDrvNamは自作ですが、エラー解析でコードを見返した際に少し違和感が
ありました。ご指摘の通りに改修すべきですね。


> 先の投稿と合わせると、発生箇所とおぼしきは:
>  (1) 「New VolumeDeviceClass()」によるインスタンス生成
この行でブレイクしてvolumeDeviceClass.Devicesをみると
エラーが入っていました。Win7(64bit)にUsbEject.Libraryが
対応していないのではと推測します。

[ツリー表示へ]
タイトルRe^5: VolumeDeviceClassで「〜バッファが無効です」エラー【解決】
記事No11424
投稿日: 2015/05/15(Fri) 21:12
投稿者Kobaちゃん
解決マークを入れ忘れていました。
また活用させて頂きます。よろしくお願いします。
魔界の仮面弁士さんありがとうございました。

> エラーの原因らしきものが判りました。
>
> 問題のPCはWin7ですが、64bit版でした。UsbEject.exe単独で実行してもWindowsエラー
> がでて停止しました。UsbEject.exeは対応していないのかもしれません。
> 単体でも動作しないのでWin7(64bit)での動作はあきらめます。
> この質問は一旦ここで解決とさせて頂きます。

[ツリー表示へ]
タイトルRe^5: VolumeDeviceClassで「〜バッファが無効です」エラー
記事No11425
投稿日: 2015/05/16(Sat) 14:21
投稿者魔界の仮面弁士
> 問題のPCはWin7ですが、64bit版でした。UsbEject.exe単独で実行してもWindowsエラー
> がでて停止しました。UsbEject.exeは対応していないのかもしれません。

32bit 向けコードで、64bit環境では動かない(とはいえ、簡単な修正で動くだろう)などと
書かれていましたね。

検索してみたら修正版が見つかりました。
http://www.cnblogs.com/coolkiss/p/3205124.html


> > Nothing / vbNullString / vbNullChar / "" などでしょう。
> > (それぞれの違いは分かりますか?)
> ネットで調べてみます。

vbNullString は、
 Dim vbNullString As String = Nothing
に相当します。(実際には変数ではなく定数ですが)
Nothing と同じ「参照なし」の意味ですが、 String 型であることが明示されています。

vbNullChar は、
 Dim vbNullChar As Char = ChrW(0)
に相当します。こちらは コード0 な 1 文字を示す物です。

"" は、ご存じのように長さ 0 の文字列。
Nothing とは違い、String 型のインスタンスとして存在しています。

[ツリー表示へ]
タイトルRe^6: VolumeDeviceClassで「〜バッファが無効です」エラー
記事No11426
投稿日: 2015/05/16(Sat) 17:50
投稿者Kobaちゃん
>32bit 向けコードで、64bit環境では動かない(とはいえ、簡単な修正で動くだろう)などと
>書かれていましたね。
> 検索してみたら修正版が見つかりました。
> http://www.cnblogs.com/coolkiss/p/3205124.html

情報ありがとうございます。
簡単な修正とは思いませんでしたが、今回の質問とは違うので「解決」とさせた頂きました。
実機が手元にないため来週になりますが。。。

(話は戻りますが)

CODE PROJECTにあるSimon Mourierさんのソースコードをもう入手できなくなり
ましたが(DLできずエラーが出ました)下記サイトにありました。
実行画面を見る限り同じものかと?

www.newxing.com/Code/CSharp/xitong/1820.html
※http〜を付けたら「そのURL形式では投稿できません」の警告が出ましたので省略しました。

C#のコードを修正版に差し替えてコンパイルしたUsbEject.exeをVBで参照すると
いう手順だと思います。
C#は初めてなのでちょっと手こずるかもしれませんが頑張ってみます。

> vbNullString は、
>  Dim vbNullString As String = Nothing
> に相当します。(実際には変数ではなく定数ですが)
> Nothing と同じ「参照なし」の意味ですが、 String 型であることが明示されています。
>
> vbNullChar は、
>  Dim vbNullChar As Char = ChrW(0)
> に相当します。こちらは コード0 な 1 文字を示す物です。
>
> "" は、ご存じのように長さ 0 の文字列。
> Nothing とは違い、String 型のインスタンスとして存在しています。

解説ありがとうございます。

ポインタが関係しているのですよね。
1.vbNullString:可変長文字列型ポインタの参照先が未定義
2.vbNullChar  :1バイト文字型ポインタの参照先が定義されており、Null文字(コード0)を参照
3.""      :可変長文字列型ポインタの参照先が定義されており、長さ 0 の文字列を参照
ではと認識しています。間違っていたらすみません。

魔界の仮面弁士さん、
親切なアドバイス、重ね重ねありがとうございます!
3年ぶりにこのプログラムをいじり始めましたが、頑張ってトライします!!

[ツリー表示へ]