Pergunta

Eu estou lidando com um conjunto de funções nativas que os dados de retorno através de matrizes alocados dinamicamente. As funções ter um ponteiro de referência como entrada, em seguida, apontar para a matriz resultante.

Por exemplo:

typedef struct result
{
   //..Some Members..//
}

int extern WINAPI getInfo(result**);

Após a chamada, 'resultado' aponta para uma matriz terminada em null de resultado *.

Eu quero criar uma lista gerenciado a partir desta matriz não gerenciada. Eu posso fazer o seguinte:

struct Result
{
   //..The Same Members..//
}

public static unsafe List<Result> getManagedResultList(Result** unmanagedArray)
{
    List<Result> resultList = new List<Result>();

    while (*unmanagedArray != null)
    {
       resultList.Add(**unmanagedArray);
       ++unmanaged;
    }
    return result;
}

Isso funciona, será entediante e feio reimplementar para cada tipo de estrutura que eu vou ter que lidar com (~ 35). Eu gostaria de uma solução que é genérico sobre o tipo de estrutura na matriz. Para esse fim, eu tentei:

public static unsafe List<T> unmanagedArrToList<T>(T** unmanagedArray)
{ 
    List<T> result = new List<T>();
    while (*unmanagedArray != null)
    {
        result.Add((**unmanagedArray));
        ++unmanagedArray;
    }
    return result;
}

Mas isso não irá compilar porque você não pode "tomar o endereço de, obter o tamanho, ou declarar um ponteiro para um tipo gerenciado ( 'T')".

Eu também tentei fazer isso sem usar código inseguro, mas eu corri para o problema que Marshal.Copy () precisa saber o tamanho da matriz não gerenciada. Eu só podia determinar isso usando o código inseguro, por isso, não parecia haver nenhum benefício para usando Marshal.Copy () neste caso.

O que eu estou ausente? Alguém poderia sugerir uma abordagem genérica para este problema?

Foi útil?

Solução

Você pode fazer uma suposição razoável que o tamanho ea representação de todos os ponteiros é o mesmo (não sei se C # especificação garante isso, mas na prática você vai encontrá-lo para ser o caso). Então você pode tratar o seu T** como IntPtr*. Além disso, eu não vejo como Marshal.Copy iria ajudá-lo aqui, uma vez que só tem sobrecargas para tipos built-in. Assim:

public static unsafe List<T> unmanagedArrToList<T>(IntPtr* p)
{ 
    List<T> result = new List<T>();
    for (; *p != null; ++p)
    {
        T item = (T)Marshal.PtrToStructure(*p, typeof(T));
        result.Add(item);
    }
    return result;
}

É claro que você vai precisar de uma conversão explícita para IntPtr* sempre que você chamar isso, mas pelo menos não há duplicação de código contrário.

Outras dicas

Você disse:

Marshal.Copy () precisa saber o tamanho da matriz não gerido. Eu só podia determinar isso usando o código inseguro

Parece que você está perdendo Marshal.SizeOf () .

Do que você mencionou no post, que pode ser suficiente para resolver o seu problema. (Além disso, o parâmetro da sua função pode precisar de ser objeto ** em vez de T **).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top