Domanda

ho a che fare con una serie di funzioni native che restituiscono dati attraverso le matrici in modo dinamico-assegnati. Le funzioni prendono un puntatore di riferimento come input, quindi puntare alla matrice risultante.

Ad esempio:

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

int extern WINAPI getInfo(result**);

Dopo la chiamata, 'risultato' indica un array null-terminata del risultato *.

Voglio creare un elenco gestito da questo array non gestito. Posso fare quanto segue:

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;
}

Questo funziona, sarà noioso e brutto per reimplementare per ogni tipo di struct che dovrò fare con (~ 35). Vorrei una soluzione che è generica sul tipo di struct nella matrice. A tal fine, ho provato:

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

Ma che non verrà compilato perché non si può "prendere l'indirizzo, ottenere la dimensione di, o dichiarare un puntatore a un tipo gestito ( 'T')".

Inoltre ho provato a fare questo senza usare codice non sicuro, ma mi sono imbattuto nel problema che Marshal.Copy () ha bisogno di conoscere la dimensione dell'array non gestito. Potrei solo determinare questo codice non sicuro utilizzando, quindi non sembrava esserci alcun vantaggio di utilizzare Marshal.Copy () in questo caso.

Che cosa mi manca? Qualcuno potrebbe suggerire un approccio generico a questo problema?

È stato utile?

Soluzione

È possibile effettuare una ragionevole ipotesi che le dimensioni e la rappresentazione di tutti i puntatori è la stessa (non so se C # garanzie spec questo, ma in pratica lo troverete sia il caso). Così si può trattare il vostro T** come IntPtr*. Inoltre, non vedo come Marshal.Copy potrebbe aiutare qui, dal momento che ha solo sovraccarichi per i tipi built-in. Quindi:

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;
}

Naturalmente avrete bisogno di un cast esplicito a IntPtr* ogni volta che si chiama questo, ma almeno non c'è alcuna duplicazione del codice altrimenti.

Altri suggerimenti

Hai detto:

  

Marshal.Copy () ha bisogno di conoscere le dimensioni   della matrice non gestito. Ho potuto solo   determinare questo codice non sicuro utilizzando

Sembra che vi state perdendo Marshal.SizeOf () .

Da quello che hai citato nel post, che potrebbe essere sufficiente a risolvere il problema. (Inoltre, il parametro della funzione può essere necessario Oggetto ** invece di T **.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top