DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ダイヤルアップ一覧の取得について

環境/言語:[WindowsXP,.NET Framework1.1]
分類:[.NET]

ダイヤルアップ設定の名称一覧を取得を行なうプログラムを
作成しています。
APIのRasEnumEntries()を使用して取得しようとしているのですが、
RasEnumEntries()が成功せずに困っています。
戻り値に9xxxxxxxxxや5xxxxxxxxxが返ってきます。
VB6.0では出来たのですが、.netではどのようにすればよいのでしょうか?
どなたかご教授の程、宜しくお願いします。

環境
WindowsXP
VB.NET
.NET Framework1.1

VB.NET-ソース-
'宣言
Private Structure RASENTRYNAME
Dim dwSize As Long
Dim szEntryName As String
Dim dwFlags As Long
Dim szPhonebookPath As String
End Structure
'API宣言
Private Declare Function RasEnumEntries Lib "RasApi32" Alias "RasEnumEntriesA" _
(ByVal reserved As Long, _
ByVal lpszPhonebook As String, _
ByVal lprasentryname As RASENTRYNAME, _
ByVal lpcb As Long, _
ByVal lpcEntries As Long) As Long
'---------------------------------------------------
'ダイヤルアップ一覧取得関数
Private Function GetEnumEntries() As Long
Dim lngRet As Long
Dim lpcb As Long
Dim lpcEntries As Long
Dim lprasentryname(0) As RASENTRYNAME '登録は1つ

lprasentryname(0).dwSize = System.Runtime.InteropServices.Marshal.SizeOf(lprasentryname(0))
lngRet = RasEnumEntries(vbNull, vbNullString, lprasentryname(0), lpcb, lpcEntries)

'以下取得--

End Function
じゃんぬねっと です。

■No8587に返信(めぐどんさんの記事)
> '宣言
> Private Structure RASENTRYNAME
> Dim dwSize As Long
> Dim szEntryName As String
> Dim dwFlags As Long
> Dim szPhonebookPath As String
> End Structure

> 'API宣言
> Private Declare Function RasEnumEntries Lib "RasApi32" Alias "RasEnumEntriesA" _
> (ByVal reserved As Long, _
> ByVal lpszPhonebook As String, _
> ByVal lprasentryname As RASENTRYNAME, _
> ByVal lpcb As Long, _
> ByVal lpcEntries As Long) As Long

まず、Long (Int64) ではなく Integer (Int32) ではないのでしょうか?
■No8588に返信(じゃんぬねっとさんの記事)

> まず、Long (Int64) ではなく Integer (Int32) ではないのでしょうか?

確かにそうでした。
ご指摘ありがとうございます。

関数の戻り値をIntegerにしたところ632が返ってきました。
構造体のサイズが間違っているということだと思うのですが、
以下だけでは駄目なのでしょうか?
lprasentryname(0).dwSize = System.Runtime.InteropServices.Marshal.SizeOf(lprasentryname(0))
よろしくお願いします。
じゃんぬねっと です。

■No8596に返信(めぐどんさんの記事)
> 関数の戻り値をIntegerにしたところ632が返ってきました。
> 構造体のサイズが間違っているということだと思うのですが、
> 以下だけでは駄目なのでしょうか?

こちらを参照してください。(VB6 ですが)
http://homepage1.nifty.com/MADIA/vb/vb_bbs/200310_03100168.html
■No8597に返信(じゃんぬねっとさんの記事)
> じゃんぬねっと です。
> こちらを参照してください。(VB6 ですが)
> http://homepage1.nifty.com/MADIA/vb/vb_bbs/200310_03100168.html

上記を参考にしてVB6.0では確認済みなのですが、
.netにした際の構造体が悪いということでしょうか?
よろしくお願いします。
RAS は扱ったことがないのですが、気になった点を少し。

> .netにした際の構造体が悪いということでしょうか?

 念のために確認です。 No8596 では
> 関数の戻り値をIntegerにしたところ
と仰ってますけど、引数や構造体の Long は変更してない‥‥ということはないですよね?


 また、 RasEnumEntries の第三、第四、第五引数は ByVal ではなく ByRef として宣言してみてください。じゃんぬねっとさんからご紹介のあったリンク先のコードでは、そのようになっているようですから。
# ByVal / ByRef を省略すると VB6 では ByRef として扱われました。< VB.NET では ByVal として扱われます。


 これだけで動作しないようでしたら、適切な属性を付ける必要があるでしょう。

プラットフォーム呼び出しによるデータのマーシャリング
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpguide/html/cpconmarshalingdatawithplatforminvoke.asp



[おまけ]
 参考になるかも知れないやりとり。
#ちゃんと読んでませんけど(^_^;)

RasEnumEntries - incorrect struct size ??
http://www.mcse.ms/archive107-2004-3-519166.html
2005/01/23(Sun) 09:25:47 編集(投稿者)

■No8599に返信(めぐどんさんの記事)
>
こんにちは 平ちゃんです


> 上記を参考にしてVB6.0では確認済みなのですが、
> .netにした際の構造体が悪いということでしょうか?
> よろしくお願いします。

構造体の何が悪いと考えているのでしょうか?
悪いと思うところを試してみればいいだけでは?

#構造体のメモリ割付は属性で指定できます。
#基本的なことなので”知ってる!”て怒られそうですが念のため
2005/01/23(Sun) 14:57:24 編集(投稿者)

他の方も指摘しておられますが、宣言側の ByVal / ByRef の違いに気をつけてください。

また、RASENTRYNAME 構造体の String 型メンバに、文字列の長さが全く指定されて
いませんので、MarshalAs属性クラスで、ByValTStrとSizeConstを追加してください。


>     lngRet = RasEnumEntries(vbNull, vbNullString, lprasentryname(0), lpcb, lpcEntries)
この呼び方にも問題があります。

この API の宣言を SDK で確認すると、
DWORD RasEnumEntries (
  LPCTSTR reserved,               // 予約済み、NULL を指定
  LPTCSTR lpszPhonebook,          // 電話帳ファイルのフルパス名とファイル名
  LPRASENTRYNAME lprasentryname,  // 電話帳エントリが格納されるバッファ
  LPDWORD lpcb,                   // バッファのバイト単位のサイズ
  LPDWORD lpcEntries              // バッファに書き込まれたエントリの数
);
となっていますよね。

現状の呼び出し側のコードについては、ここに vbNull という値を渡しています。
しかし vbNull は、数値でいえば 1 に相当する物であり、明らかに異なる値です。

最初の引数に指定するべきは、本来は(Cでいうところの)NULLです。
これは VBでは Nothing に相当します。今回は整数型で宣言されておられるので、「0」を渡してください。


# そもそも vbNull は、VarType 関数の戻り値として利用されるものであって、
# こういう所で使うような物ではありませんよ。
下のソースで動作できるようになりました。
まだまだマーシャリング等々勉強することが多いようです。
じゃんぬねっと様,深山 ファミリー様,平ちゃん様,魔界の仮面弁士様
親切にご回答頂き、本当にありがとうございました。

'構造体宣言
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Public Structure RASENTRYNAME
Dim dwSize As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=257 + 1)> _
Dim entryName As String
Dim flags As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260 + 1)> _
Dim phonebookPath As String
End Structure

'API宣言
Public Declare Auto Function RasEnumEntries Lib "rasapi32.dll" ( _
ByVal reserved As String, _
ByVal phonebook As String, _
<[In](), Out()> ByVal rasEntryNames() As RASENTRYNAME, _
ByRef cntBytes As Integer, _
ByRef cntEntries As Integer _
) As Integer


'ダイヤルアップ一覧取得関数内
Dim entries() As RASENTRYNAME
Dim cntBytes As Integer
Dim cntEntries As Integer

    ReDim entries(0)
entries(0).dwSize = Marshal.SizeOf(GetType(RASENTRYNAME))
cntBytes = entries(0).dwSize * 1
rtn = RasEnumEntries(vbNullString, vbNullString, _
entries, cntBytes, cntEntries)
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板