tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルグループ名の取得について
記事No1185
投稿日: 2004/12/02(Thu) 14:42
投稿者Hamiltonian
[OSのVer]:WindowsXP Pro     [VBのVer]:VB.NET

こんにちは。
以前「Unicode変換について」という質問をさせていただきました。
申し訳ないのですが、また同じような質問をさせていただきます。

順を追って説明しますと、VB6からVB.NETへの移行を行った際、
ユーザーがAdministrator権限を持っているかを判定する関数があるのですが、
そこで使用しているAPI関数のNetUserGetLocalGroupsが移行後、
機能しなくなってしまいました。
原因は、この関数は引数をUnicodeで渡さなくてはならず、
VB6ではそのためStrConv([文字列],vbUnicode)を使用していました。
しかしVB.NETではオプションのvbUnicodeがなくなってしまったため、
正しく移行されませんでした。

これに対し、魔界の仮面弁士さんに
@VB.NETの場合、宣言時に文字列の扱いを明示できるので、そこでUnicodeを指定すればいい。
ANetUserGetLocalGroupsを使わずに、Administrator権限を判定する関数例。
と二通りの回答をいただきました。
結果、Aの提案していただいた関数を採用することで解決しました。

今回質問したいのは、この関数はそのまま使うとローカルマシンに対して判定を行うので、
ほかのマシンにも判定を行うよう変更を加えようと試みましたが、まったくわかりませんでした。
そこで、上記@の提案を取り入れてみたところ、NetUserGetLocalGroups関数は
正しい戻り値を返すようになったのですが、その後の処理がVB6とは
異なった結果になってしまいます。
この原因がわからず困っています。

以下は某サイトを参考に作成し、.NETに移行した実際の関数コードです。
どの部分に問題があるのかご指摘いただけるとうれしくおもいます。
よろしくお願いします。


---------------------------------------------------------------------------------
'指定されたユーザーが所属するローカルグループのリストを取得する関数の宣言
Public Declare Unicode Function NetUserGetLocalGroups Lib "netapi32.dll" (ByVal
ServerName As String, ByVal username As String, ByVal level As Integer, ByVal flag As
Integer, ByRef bufptr As Integer, ByVal prefmaxlen As Integer, ByRef entriesread As
Integer, ByRef totalentries As Integer) As Integer

'メモリを解放する関数の宣言
Public Declare Function NetApiBufferFree Lib "netapi32.dll" (ByVal Buffer As Int
eger) As
Integer

'メモリを移動する関数の宣言
Public Declare Sub RtlMoveMemory Lib "Kernel32.dll" (ByRef Destination As Intege
r, ByRef
Source As Integer, ByVal Length As Integer)

'文字列をコピーする関数の宣言
Public Declare Function lstrcpy Lib "Kernel32.dll"  Alias "lstrcpyW"(B
yRef lpszString1 As
Byte, ByRef lpszString2 As Integer) As Integer

'文字列の長さを返す関数の宣言
Public Declare Function lstrlen Lib "Kernel32.dll"  Alias "lstrlenW"(B
yVal lpszString As
Integer) As Integer

'ローカルグループ情報を格納する構造体
Public Structure LOCALGROUP_USER_INFO_0
  Dim lgrui0_name As Integer
End Structure

Public Const LG_INCLUDE_INDIRECT As Short = &H1s
Public Const MAX_PREFERRED_LENGTH As Short = -1
Public Const ERROR_MORE_DATA As Short = 234
Public Const NERR_Success As Short = 0


Public Function GfAdminChk() As Boolean

  Dim lngWin32apiResultCode As Integer
  Dim strServerName As String
  Dim strUserName As String
  Dim lngBufPtr As Integer
  Dim lngEntriesRead As Integer
  Dim lngTotalEntries As Integer
  Dim lngResumeHandle As Integer
  Dim udtGInfo0 As LOCALGROUP_USER_INFO_0
  Dim lngEntry As Integer
  Dim strGroup As String

  GfAdminChk = False
  
  ' サーバー名を設定(空文字の場合はローカルコンピュータ)
  strServerName = "AAA"

  ' ユーザー名
  strUserName = "BBB"

  ' ローカルグループのリストを取得する
  lngWin32apiResultCode = NetUserGetLocalGroups(strServerName, strUserName, 0,
LG_INCLUDE_INDIRECT, lngBufPtr, MAX_PREFERRED_LENGTH, lngEntriesRead, lngTotalEntries)
  ' リストの取得に成功したときは
  If (lngWin32apiResultCode = NERR_Success) Or (lngWin32apiResultCode = ERROR_MORE_DATA)
Then
   For lngEntry = 0 To lngEntriesRead - 1
    ' バッファを構造体にコピー
    RtlMoveMemory(udtGInfo0.lgrui0_name, lngBufPtr + Len(udtGInfo0.lgrui0_name) *
lngEntry, Len(udtGInfo0.lgrui0_name))
    strGroup = PointerToString(udtGInfo0.lgrui0_name)
    If strGroup = "Administrators" Then
     GfAdminChk = True
    End If
   Next
  End If
  ' メモリを解放
  If lngBufPtr <> 0 Then
   NetApiBufferFree(lngBufPtr)
  End If
  
End Function


Function PointerToString(ByRef lngPointer As Integer) As String
  'ポインタを文字列に変換
  Dim bytBuffer(255) As Byte
  
  'ポインタが指す文字列をバイト配列へコピー
  lstrcpy(bytBuffer(0), lngPointer)
  'null文字以降を切り捨て
  PointerToString = Left(System.Text.UnicodeEncoding.Unicode.GetString(bytBuffer), lstrlen
(lngPointer))
  
End Function
---------------------------------------------------------------------------------

[ツリー表示へ]
タイトルRe: グループ名の取得について
記事No1217
投稿日: 2004/12/09(Thu) 13:30
投稿者魔界の仮面弁士
> 以前「Unicode変換について」という質問をさせていただきました。
どれの事かわかるよう、記事番号を併記すると良いかも。

> その後の処理がVB6とは異なった結果になってしまいます。
文字列のマーシャリングに問題があるような…。


> 以下は某サイトを参考に作成し、.NETに移行した実際の関数コードです。
某サイトって、vbvbvb.com ですよね。スペルミスまでそのまま写されてます。(汗)


NetUserGetLocalGroups API を呼ぶなら、こんな感じでどうですかね。


Imports System.Runtime.InteropServices
Namespace Orator.Win32
    Public Class Network
        Private Const LG_INCLUDE_INDIRECT As Integer = &H1I
        Private Const MAX_PREFERRED_LENGTH As Integer = -1I
        Private Enum NET_API_STATUS As Integer
            ERROR_ACCESS_DENIED = 5I
            ERROR_MORE_DATA = 234I
            RPC_S_SERVER_UNAVAILABLE = 1722I
            NERR_InvalidComputer = 2351I
            NERR_UserNotFound = 2221I
            NERR_Success = 0I
        End Enum
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
        Private Structure LOCALGROUP_USERS_INFO_0
            Public lgrui0_name As String
        End Structure
        Private Declare Unicode Function NetUserGetLocalGroups Lib "netapi32" _
            (ByVal ServerName As String, _
             ByVal username As String, _
             ByVal level As Integer, _
             ByVal flag As Integer, _
             ByRef bufptr As IntPtr, _
             ByVal prefmaxlen As Integer, _
             ByRef entriesread As Integer, _
             ByRef totalentries As Integer) As NET_API_STATUS
        Private Declare Function NetApiBufferFree Lib "netapi32" (ByVal Buffer As IntPtr) As Integer
        Public Overloads Shared Function GetLocalGroups(ByVal UserName As String) As String()
            Return GetLocalGroups(Nothing, UserName)
        End Function
        Public Overloads Shared Function GetLocalGroups(ByVal ServerName As String, ByVal UserName As String) As String()
            Dim List() As String = New String() {}
            Dim BufPtr As IntPtr = IntPtr.Zero
            Try
                Dim EntriesRead, TotalEntries As Integer
                Dim Result As NET_API_STATUS = NetUserGetLocalGroups(ServerName, UserName, 0, LG_INCLUDE_INDIRECT, BufPtr, MAX_PREFERRED_LENGTH, EntriesRead, TotalEntries)
                If (Result = NET_API_STATUS.NERR_Success) OrElse (Result = NET_API_STATUS.ERROR_MORE_DATA) Then
                    Dim P As IntPtr = BufPtr
                    ReDim List(EntriesRead - 1)
                    For Entry As Integer = 0 To EntriesRead - 1
                        Dim GInfo0 As LOCALGROUP_USERS_INFO_0 = DirectCast(Marshal.PtrToStructure(P, GetType(LOCALGROUP_USERS_INFO_0)), LOCALGROUP_USERS_INFO_0)
                        List(Entry) = GInfo0.lgrui0_name.ToString()
                        P = New IntPtr(P.ToInt32() + Marshal.SizeOf(GetType(LOCALGROUP_USERS_INFO_0)))
                    Next
                ElseIf Result = NET_API_STATUS.ERROR_ACCESS_DENIED Then
                    Throw New System.Exception("ユーザーには、要求した情報へのアクセス権がありません。")
                ElseIf Result = NET_API_STATUS.NERR_InvalidComputer Then
                    Throw New System.Exception("コンピュータ名が無効です。")
                ElseIf Result = NET_API_STATUS.NERR_UserNotFound Then
                    Throw New System.Exception("指定されたユーザー名が見つかりませんでした。 ")
                ElseIf Result = NET_API_STATUS.RPC_S_SERVER_UNAVAILABLE Then
                    Throw New System.Exception("RPC サーバーを利用できません。")
                Else
                    Throw New System.Exception("NetUserGetLocalGroups : 0x" & Result.ToString("x"))
                End If
            Finally
                If Not IntPtr.Zero.Equals(BufPtr) Then
                    NetApiBufferFree(BufPtr)
                    BufPtr = IntPtr.Zero
                End If
            End Try
            Return List
        End Function
    End Class
End Namespace

[ツリー表示へ]
タイトルRe^2: グループ名の取得について
記事No1220
投稿日: 2004/12/13(Mon) 09:14
投稿者Hamiltonian
回答していただきありがとうございます。大変助かります。
恥ずかしい限りですが、参考にさせていただきます。

[ツリー表示へ]