トップ回答者
APIが動作してくれません

質問
-
初めてAPIを使用しているのですが、思うように動作してくれません。
問題が発生しているのは”GetLogicalDriveStrings”という関数を使用した以下の部分です。Private Declare Function GetLogicalDriveStrings Lib "kernel32" _
Alias "GetLogicalDriveStringsA" _
(ByVal nBufferLength As Long, ByVal lpBuffer As String) As LongPrivate Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim sbuffer As String
Dim result As Boolean
sbuffer = Space(105)
result = GetLogicalDriveStrings(Len(sbuffer), sbuffer)
End SubAPI関数を使用している行で「保護されているメモリに読み取りまたは書き込み操作を行おうとしました。
他のメモリが壊れていることが考えられます。」というエラーになってしまいます。
引数に設定しているバッファメモリーのポインターに問題があるのかと思い、いろいろ変更して試してみたのですが、
解決できません。
APIに詳しい方、アドバイス頂けたら助かります。
回答
-
As LongがAs Integerであることの他に、As Stringがまずいと思います。
.NETではStringは固定のもので、中身をAPIに渡して書き換えるといったことはできません。
pinvoke.netを参照すると、char配列にしてはどうかという記述もあるので参考にして下さい。
http://www.pinvoke.net/default.aspx/kernel32/GetLogicalDriveStrings.html?diff=y
C#でのコードサンプル
Code Snippetstatic extern int GetLogicalDriveStrings(int nBufferLength, [Out] char[] lpBuffer);
static void Main()
{
int nBufferLength = 255;
char[] lpBuffer = new char[nBufferLength];
GetLogicalDriveStrings(nBufferLength, lpBuffer);
}http://labs.developerfusion.co.uk/convert/csharp-to-vb.aspx で変換して参考にしてみて下さい。
※動作が正しいかどうか、構文として適切かどうかについては評価していません。
-
私がやるかぎり、Stringで書き換えてくれますよ。
以下のコードでもできました。
Code SnippetPrivate Declare Function GetLogicalDriveStrings Lib "kernel32" _
Alias "GetLogicalDriveStringsA" _
(ByVal nBufferLength As Integer, ByVal lpBuffer As IntPtr) As LongPrivate Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim sbuffer As String
Dim result As Boolean
sbuffer = Space(105)Dim p As IntPtr
p = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(sbuffer)
result = GetLogicalDriveStrings(Len(sbuffer), p)
sbuffer = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(p)
System.Runtime.InteropServices.Marshal.FreeHGlobal(p)
MsgBox(sbuffer)
End Sub -
すべての返信
-
As LongがAs Integerであることの他に、As Stringがまずいと思います。
.NETではStringは固定のもので、中身をAPIに渡して書き換えるといったことはできません。
pinvoke.netを参照すると、char配列にしてはどうかという記述もあるので参考にして下さい。
http://www.pinvoke.net/default.aspx/kernel32/GetLogicalDriveStrings.html?diff=y
C#でのコードサンプル
Code Snippetstatic extern int GetLogicalDriveStrings(int nBufferLength, [Out] char[] lpBuffer);
static void Main()
{
int nBufferLength = 255;
char[] lpBuffer = new char[nBufferLength];
GetLogicalDriveStrings(nBufferLength, lpBuffer);
}http://labs.developerfusion.co.uk/convert/csharp-to-vb.aspx で変換して参考にしてみて下さい。
※動作が正しいかどうか、構文として適切かどうかについては評価していません。
-
私がやるかぎり、Stringで書き換えてくれますよ。
以下のコードでもできました。
Code SnippetPrivate Declare Function GetLogicalDriveStrings Lib "kernel32" _
Alias "GetLogicalDriveStringsA" _
(ByVal nBufferLength As Integer, ByVal lpBuffer As IntPtr) As LongPrivate Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim sbuffer As String
Dim result As Boolean
sbuffer = Space(105)Dim p As IntPtr
p = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(sbuffer)
result = GetLogicalDriveStrings(Len(sbuffer), p)
sbuffer = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(p)
System.Runtime.InteropServices.Marshal.FreeHGlobal(p)
MsgBox(sbuffer)
End Sub -
-
配列で受け取る場合 マーシャリングをANSIにすると Byte配列にしないとうまく受け取れないようです
Code SnippetPrivate Declare Function GetLogicalDriveStrings2 Lib "kernel32" _
Alias "GetLogicalDriveStringsA" _
(ByVal nBufferLength As Integer, ByVal lpBuffer() As Byte) As Integer
Private Declare Auto Function GetLogicalDriveStrings Lib "kernel32" _
(ByVal nLength As Integer, ByVal lpBuuf() As Char) As IntegerAutoにするか AliasでUnicode版を指定すればChar配列で受けと取れます
Code Snippetdim nLen as Integer
dim ch(256) as Char
dim sDrives() as string, sb as new StringBuilder
nLen = GetLogicalDriveStrings( ch.Length, ch )
for n as integer = 0 to nLen
if ch(n) = nothing then ch(n) = ";"
next
sb.Appned( ch, 0, nLen )
sDrives = sb.TOString.Split( ";".ToCharArry, System.StringSplitOptions.RemoveEmptyEntries )
といった具合で sDrivesに 『C:\』 『D:\』 などを取得出来ます
Ansiでやるなら
Code SnippetDim bb(256) as Byte
dim ch(256) as Char
dim nLen as Integer
dim sb as new System.Text.StringBulder, sDrive() as string
Dim dd as System.Text.Decorder = System.Text.Defualt.GetDecorder
nLen = GetLogicalDriveString2( bb.Length, bb )
dd.GetChars( bb, 0, nLen, ch, 0 )
for n as Integer = 0 to nLen
if ch(n) = nothing then ch()n) = ";"
next
sb.Appned( ch, 0, nLen )
sDrives = sb.TOString.Split( ";".ToCharArry, System.StringSplitOptions.RemoveEmptyEntries )
といった具合です