WNetEnumResource リソースの列挙

Cの宣言:

DWORD WNetOpenEnum(
	HANDLE hEnum,
	LPDWORD ResNum,
	LPVOID Buf,
	LPDWORD BufSize);

説明:

WNetOpenEnumで取得した列挙ハンドルhEnumを元に、リソースの列挙を(継続して)行う。

引数の意味は以下の通り。
hEnum (IN) 列挙ハンドル。
ResNum (IN/OUT) 返されるリソース情報の数。関数の実行後、実際に返されたリソースの数が設定される。
Buf (OUT) 取得結果のリソース情報を示すNETRESOURCE構造体の配列。
BufSize (IN/OUT) Bufのサイズ。Bufが小さすぎる場合、必要なサイズが返される。

戻り値は、発生したエラーを表すエラー値である。

Cのサンプル:

“FOOBAR”というドメインに属している全てのマシンの名前を表示する。
void DispMachines()
{
	NETRESOURCE parent;
	LPNETRESOURCE pnr;
	HANDLE hEnum;
	DWORD BufSize;
	DWORD ResNum;

	ZeroMemory(&parent, sizeof(parent));
	pnr = GlobalAlloc(GMEM_FIXED, 1000);

	parent.dwScope = RESOURCE_GLOBALNET;
	parent.dwType = RESOURCETYPE_ANY;
	parent.dwDisplayType = RESOURCEDISPLAYTYPE_DOMAIN;
	parent.dwUsage = RESOURCEUSAGE_CONTAINER;
	parent.lpRemoteName = "FOOBAR";
	parent.lpProvider = "Microsoft Windows Network";

	WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, &parent, &hEnum);

	while(BufSize = 1000, ResNum = 1, WNetEnumResource(hEnum, &ResNum, pnr, &BufSize) == NO_ERROR) {
		printf("%s\n", pnr->lpRemoteName);
	}

	WNetCloseEnum(hEnum);

	GlobalFree(pnr);
}

VBのサンプル:

下記サンプルでは、メインフォームfrmMain上に、tvwNetViewという名前のツリービューコントロールがある。フォームのロード時に、ツリービュー上にネットワークプロバイダを表すノードが表示される。ツリービューのExpandイベント発生時に、WNetEnumResourceなどによって子ネットワークリソース群を表すノードを追加することにより、エクスプローラの「ネットワークドライブの割り当て」ダイアログボックスのような、階層的なネットワークリソースの表示を行う。
------------------ 以下は、modAPI.bas のソース ------------------
Option Explicit

Public Type NETRESOURCE
    dwScope As Long
    dwType As Long
    dwDisplayType As Long
    dwUsage As Long
    lpLocalName As Long
    lpRemoteName As Long
    lpComment As Long
    lpProvider As Long
    buf(1000) As Byte
End Type

Public Const RESOURCE_GLOBALNET As Long = 2
Public Const RESOURCETYPE_ANY As Long = 0
Public Const RESOURCEUSAGE_CONTAINER As Long = 2

Public Const ERROR_NO_MORE_ITEMS As Long = 259
Public Const NO_ERROR As Long = 0

Public Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000
Public Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = &H200
Public Const DEFAULT_LANG_ID As Long = &H400

Declare Function WNetOpenEnum Lib "mpr" Alias "WNetOpenEnumA" ( _
    ByVal ResScope As Long, _
    ByVal ResType As Long, _
    ByVal ResUsage As Long, _
    ByRef Res As NETRESOURCE, _
    ByRef hEnum As Long) As Long

Declare Function WNetOpenEnumForRoot Lib "mpr" Alias "WNetOpenEnumA" ( _
    ByVal ResScope As Long, _
    ByVal ResType As Long, _
    ByVal ResUsage As Long, _
    ByVal pRes As Long, _
    ByRef hEnum As Long) As Long

Declare Function WNetCloseEnum Lib "mpr" (ByVal hEnum As Long) As Long

Declare Function WNetEnumResource Lib "mpr" Alias "WNetEnumResourceA" ( _
    ByVal hEnum As Long, _
    ByRef EntryNum As Long, _
    ByRef buf As NETRESOURCE, _
    ByRef BufSize As Long) As Long

Declare Function lstrcpyFromPtr Lib "kernel32" Alias "lstrcpyA" (ByVal S As String, ByVal ptr As Long) As Long

Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" ( _
    ByVal Flags As Long, _
    ByVal pSource As Long, _
    ByVal MessageID As Long, _
    ByVal LangID As Long, _
    ByVal Message As String, _
    ByVal MessageSize As Long, _
    ByVal pArgs As Long) As Long
    
' ptrで指定されたアドレスに存在する文字列を取得し、結果をString型で返す
Public Function PtrToStr(ptr As Long) As String

    Dim S As String * 1000
    
    lstrcpyFromPtr S, ptr
    PtrToStr = Left(S, InStr(S, vbNullChar) - 1)

End Function

------------------ 以下は、frmMain.frm のソース ------------------
Option Explicit

Private Res(1000) As NETRESOURCE
Private ResCount As Long

Private Const RESIDX_PREFIX As String = "RESIDX:"
Private Const INTERNAL_NODE_NAME As String = "internal node"

' ツリービューに全ての子供を追加。
' ContainerIdx: 列挙元のネットワークリソース
' ParentNodeIdx: 追加先のノード
Private Sub AddChilds(ParentNodeIdx As Long, ContainterIdx As Long)

    Dim lResult As Long
    Dim ResIdx As Long
    Dim EntryNum As Long
    Dim BufSize As Long
    Dim hEnum As Long

    '列挙開始
    If ContainterIdx = -1 Then
        lResult = WNetOpenEnumForRoot(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, 0, hEnum)
    Else
        lResult = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY, 0, Res(ContainterIdx), hEnum)
    End If
    
    If lResult <> NO_ERROR Then
        DispDllError
        Exit Sub
    End If

    Do '子供を全て追加
        ResIdx = AllocNewRes()
        EntryNum = 1
        BufSize = 1000
        
        lResult = WNetEnumResource(hEnum, EntryNum, Res(ResIdx), BufSize)
        If lResult = ERROR_NO_MORE_ITEMS Then Exit Do
        If lResult <> NO_ERROR Then
            DispDllError
            Exit Do
        End If

        AddNewNode ParentNodeIdx, ResIdx
    Loop

    WNetCloseEnum hEnum

End Sub


' ツリービューにノードを追加
Private Function AddNewNode(ParentIdx As Long, ResIdx As Long) As Long
    
    Dim RemoteName As String
    Dim NewNode As Node

    RemoteName = PtrToStr(Res(ResIdx).lpRemoteName)
    
    If ParentIdx <> -1 Then
        Set NewNode = tvwNetView.Nodes.Add(tvwNetView.Nodes(ParentIdx), tvwChild, RESIDX_PREFIX & ResIdx, RemoteName)
    Else
        Set NewNode = tvwNetView.Nodes.Add(, , RESIDX_PREFIX & ResIdx, RemoteName)
    End If
    
    If (Res(ResIdx).dwUsage And RESOURCEUSAGE_CONTAINER) <> 0 Then
        tvwNetView.Nodes.Add NewNode.Index, tvwChild, , INTERNAL_NODE_NAME
    End If
    
End Function

' NETRESOURCEの配列から未使用のインデックスを取得
Private Function AllocNewRes() As Long

    ResCount = ResCount + 1
    
    'ReDim文を使用するときは、既存のデータの格納位置が移動することによって
    'lpXXが不正なポインタになる可能性があるので注意。
    
    AllocNewRes = ResCount

End Function


' APIエラーの表示
Private Sub DispDllError()

    Dim errno As Long
    Dim buf As String * 1000
    
    errno = Err.LastDllError
    errno = FormatMessage( _
        FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, _
        0, errno, DEFAULT_LANG_ID, buf, 1000, 0)
    
    MsgBox Left(buf, InStr(buf, vbNullChar) - 1), vbOKOnly Or vbExclamation

End Sub

Private Sub Form_Load()

    Dim lResult As Long
    Dim hEnum As Long
    Dim EntryNum As Long
    Dim BufSize As Long
    Dim RemoteName As String
    Dim ResIdx As Long
    
    ResCount = 0
  
    'ネットワークプロバイダをツリービューに表示しておく
    AddChilds -1, -1

End Sub


' ツリービューのノードが展開されたときは、子供を検索・追加する
Private Sub tvwNetView_Expand(ByVal Node As ComctlLib.Node)

    Dim hEnum As Long
    Dim ParentIdx As Long
    Dim lResult As Long
    Dim ResIdx As Long
    Dim EntryNum As Long
    Dim BufSize As Long

    If Node.Children > 0 Then
        If Node.Child.Text = INTERNAL_NODE_NAME Then
            tvwNetView.MousePointer = ccHourglass

            tvwNetView.Nodes.Remove Node.Child.Index
            tvwNetView.Refresh
            
            ParentIdx = CLng(Mid(Node.Key, Len(RESIDX_PREFIX) + 1))
        
            AddChilds Node.Index, CLng(Mid(Node.Key, Len(RESIDX_PREFIX) + 1))
            tvwNetView.MousePointer = ccDefault
        End If
    End If
    

End Sub

(original text:1999/03/04 更新)

本ドキュメントの内容は保証しません。本ドキュメントによって生じた結果について、一切の責任を負いません。