2017-05-10 23 views
0

WinAPI関数を使用してVB.NetアプリケーションからWindows資格情報を列挙する際に問題があります。私のコードは以下の通りです。WinAPI CredEnumerate Marshal.PtrToStructure例外

<DllImport("advapi32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)> 
Private Shared Function CredEnumerate(filter As String, flag As Integer, ByRef count As Integer, ByRef pCredentials As IntPtr) As Boolean 
End Function 

Public Enum CRED_PERSIST As UInteger 
    SESSION = 1 
    LOCAL_MACHINE = 2 
    ENTERPRISE = 3 
End Enum 

Public Enum CRED_TYPE As UInteger 
    GENERIC = 1 
    DOMAIN_PASSWORD = 2 
    DOMAIN_CERTIFICATE = 3 
    DOMAIN_VISIBLE_PASSWORD = 4 
    GENERIC_CERTIFICATE = 5 
    DOMAIN_EXTENDED = 6 
    MAXIMUM = 7 
    ' Maximum supported cred type 
    MAXIMUM_EX = (MAXIMUM + 1000) 
    ' Allow new applications to run on old OSes 
End Enum 

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> 
Public Structure CREDENTIAL_ATTRIBUTE 
    Private Keyword As String 
    Private Flags As UInteger 
    Private ValueSize As UInteger 
    Private Value As IntPtr 
End Structure 

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> 
Private Class Credential 
    Public Flags As UInt32 
    Public Type As CRED_TYPE 
    Public TargetName As String 
    Public Comment As String 
    Public LastWritten As ComTypes.FILETIME 
    Public CredentialBlobSize As UInt32 
    Public CredentialBlob As IntPtr 
    Public Persist As CRED_PERSIST 
    Public AttributeCount As UInt32 
    Public Attributes As IntPtr 
    Public TargetAlias As String 
    Public UserName As String 
End Class 


Private Function GetCredentials() As Credential() 
    Dim count As Integer = 0 
    Dim pCredentials As IntPtr = IntPtr.Zero 
    Dim credentials As List(Of Credential) = New List(Of Credential) 
    Dim ret As Boolean = CredEnumerate(Nothing, 0, count, pCredentials) 
    If ret <> False Then 
     Dim p As IntPtr = pCredentials 
     For n As Integer = 0 To count - 1 
      If Marshal.SizeOf(p) = 4 Then 
       p = New IntPtr(p.ToInt32() + n) 
      Else 
       p = New IntPtr(p.ToInt64() + n) 
      End If 
      credentials.Add(Marshal.PtrToStructure(Marshal.ReadIntPtr(p), GetType(Credential))) 
     Next 
    End If 
    Return credentials.ToArray 
End Function 

Marshal.PtrToStructure機能は、任意の有用な情報なしSystem.ExecetionEngineExceptionをスローします。私は間違った資格の構造で疑いましたが、それは私には正しいようです。何が間違っているか分かっているなら、私はあなたの答えを待っています。 ありがとう

編集:@Zagglerのおかげで、ここに私の修正された機能が追加されました。しかし、構造全体が空です。 ここに新しい機能があります。

Private Function GetCredentials() As Credential() 
    Dim count As Integer = 0 
    Dim pCredentials As IntPtr = IntPtr.Zero 
    Dim credentials As List(Of Credential) = New List(Of Credential) 

    Dim ret As Boolean = CredEnumerate(Nothing, 0, count, pCredentials) 
    If ret <> False Then 
     Dim p As IntPtr = pCredentials 
     For n As Integer = 0 To count - 1 
      Dim cred As Credential = New Credential 
      Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(cred)) 
      Try 

       If Marshal.SizeOf(p) = 4 Then 
        p = New IntPtr(p.ToInt32() + n) 
       Else 
        p = New IntPtr(p.ToInt64() + n) 
       End If 
       Marshal.StructureToPtr(cred, pnt, False) 
       credentials.Add(Marshal.PtrToStructure(pnt, GetType(Credential))) 

      Finally 
       Marshal.FreeHGlobal(pnt) 
      End Try 
     Next 
    End If 
    Return credentials.ToArray 
End Function 
+0

[** this **](https://msdn.microsoft.com/en-us/library/4ca6d5z7(v=vs.110).aspx?cs-save-lang = 1&cs-lang = vb#code-snippet-2)記事... – Codexer

+0

@Zagglerがあなたの答えに感謝します。あなたが今私に別の問題を抱えているという情報源に基づいて私のスニペットを編集しました。返された資格情報構造は空です。私は私のメインポストを編集しました。 –

+0

ああ私はCredEnumerate関数の後にCredRead関数を使用する必要があります。 –

答えて

1

あなたの最初の試みはよかったです。 AllocHGlobalとFreeHGlobalを使用しないでください。 Winapiはメモリを割り当てています。割り当てられたメモリを解放するためにCredFreeを検索します(構造体を整列した後)。

ポインタ演算に間違いがあります。ポインタサイズを増やす必要があります。

... 
Dim p As IntPtr = pCredentials 
For n As Integer = 0 To count - 1 
    credentials.Add(Marshal.PtrToStructure(Marshal.ReadIntPtr(p), GetType(Credential))) 
    p = p + IntPtr.Size 
Next 
... 

UInt32とUIntegerは同じであり、一貫性を保って選択してください。

Charset.Autoをすべて使用してみてください。動作しない場合は、Charset.Unicodeを試して、CredEnumerateW関数を使用してください。