Помогите с CredEnumerate - PullRequest
       11

Помогите с CredEnumerate

3 голосов
/ 01 ноября 2008

В качестве продолжения этого вопроса я надеюсь, что кто-нибудь может помочь с CredEnumerate API.

Как я понимаю из документации, выходной параметр PCREDENTIALS - это "указатель на массив указателей на учетные данные". Я могу успешно вызвать CredEnumerate API с использованием C #, но я не уверен, как преобразовать PCREDENTIALS во что-то полезное (например, список учетных данных).

Редактировать: вот код, который я использую:

        int count = 0;
        IntPtr pCredentials = IntPtr.Zero;
        bool ret = false;
        ret = CredEnumerate(null, 0, out count, out pCredentials);
        if (ret != false)
        {
            IntPtr[] credentials = new IntPtr[count];
            IntPtr p = pCredentials;
            for (int i = 0; i < count; i++)
            {
                p = new IntPtr(p.ToInt32() + i);
                credentials[i] = Marshal.ReadIntPtr(p);
            }
            List<Credential> creds = new List<Credential>(credentials.Length);
            foreach (IntPtr ptr in credentials)
            {
                creds.Add((Credential)Marshal.PtrToStructure(ptr, typeof(Credential)));
            }
        }

К сожалению, хотя это работает для первых учетных данных в массиве - оно генерируется и корректно добавляется в список - последующие элементы массива бомбят Marshal.PtrToStructure со следующей ошибкой:

Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена.

Есть идеи? Кто-нибудь? Bueller

Ответы [ 2 ]

5 голосов
/ 01 ноября 2008

Вам нужно разыменовать указатель на массив, чтобы получить массив, затем для каждого элемента в массиве вам нужно разыменовать этот элемент, чтобы получить экземпляр PCREDENTIALS.

Я нашел это сообщение с примером кода для выполнения того, что вы хотите сделать:

[DllImport("advapi32", SetLastError = true, CharSet=CharSet.Unicode)]
static extern bool CredEnumerate(string filter, int flag, out int count, out IntPtr
pCredentials);

...

int count = 0;
IntPtr pCredentials = IntPtr.Zero;
IntPtr[] credentials = null;
bool ret = CredEnumerate(null, 0, out count, out pCredentials);
if (ret != false)
{
    credentials = new IntPtr[count];
    IntPtr p = pCredentials;
    for (int n = 0; n < count; n++)
    {
        credentials[n] = Marshal.ReadIntPtr(pCredentials,
           n * Marshal.SizeOf(typeof(IntPtr)));
    }
} 
else
// failed....

Затем для каждого указателя вам нужно будет использовать Marshal.PtrToStructure для разыменования указателя в экземпляр структуры PCREDENTIALS (извините, я нигде не могу найти typedef для PCREDENTIALS, я предполагаю, что он у вас есть - и если вы не забудете правильные атрибуты MarshalAs и атрибут StructLayout при его определении):

// assuming you have declared struct PCREDENTIALS
var creds = new List<PCREDENTIALS>(credentials.Length);
foreach (var ptr in credentials)
{
    creds.Add((PCREDENTIALS)Marshal.PtrToStructure(ptr, typeof(PCREDENTIALS)));
}

Очевидно, вы захотите объединить пример и код PtrToStructure для получения оптимальных результатов, но я хотел оставить целостность примера без изменений.

1 голос
/ 27 января 2011

Вам также нужно правильно рассчитать IntPtr p, в приведенном выше коде отсутствует этот код, и он будет извлекать только первую структуру.

Th следующий код получит все структуры в IntPtr pCredentials

int count;
IntPtr pCredentials;

if (CredEnumerate(filter, 0, out count, out pCredentials) != 0)
{
    m_list = new List<PCREDENTIALS >(count);
    int sz = Marshal.SizeOf(pCredentials);

    for (int index = 0; index < count; index++)
    {
        IntPtr p = new IntPtr((sz == 4 ? pCredentials.ToInt32() : pCredentials.ToInt64()) + index * sz);
        m_list.Add((PCREDENTIALS)Marshal.PtrToStructure(p, typeof(PCREDENTIALS)));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...