2010-06-29 14 views
5

In un progetto C#, ho bisogno di passare i parametri dell'oggetto inserendo riferimenti in una struttura. cioè ho una struttura passata a un dispatcherConversione da vuoto * a oggetto in C#

struct SOMESTRUCT 
{ 
    public int lpObject; 
} 

Dove lpObject contiene un puntatore ad un oggetto personalizzato come

class SomeClass 
{ 
    private string foo; 
} 

E la struttura SOMESTRUCT viene passato da metodo a metodo per raggiungere finalmente il mio codice. Non riesco a modificare il flusso di esecuzione né il sistema SOMSTRUCT strana, così ho intuito l'unica soluzione era quella di gettare il mio oggetto per un puntatore come questo:

var myObject = new SomeClass(); 
GCHandle GC = GCHandle.Alloc(myObject, GCHandleType.Pinned); 
int myRef = GC.AddrOfPinnedObject().ToInt32(); 
GC.Free(); 

SOMESTRUCT struct; 
struct.lpObject = myRef; 
someMethod(struct); 

Tuttavia, non riesco a capire come recuperare i membri MyObject dai campi lpObject. Qualcosa del genere:

SomeClass myObject = CastPointerToObject(struct.myRef) as SomeClass; 

C'è un modo per farlo o è impossibile? Come posso dire al garbage collector di gestire l'oggetto? Devo creare un nuovo oggetto Garbage-collected e copiare il campo dati per campo?

TYIA,

+0

usa IntPtr invece di int ....quindi funzionerà anche a 64bit –

risposta

4

no No NO NONO !!!

Questo

struct SOMESTRUCT 
{ 
    public SomeClass object_ref; 
} 

è il modo corretto per memorizzare un riferimento in uno struct.

Il codice scritto e la risposta accettata sono danneggiati al 100%.

L'indirizzo restituito da GC.AddrOfPinnedObject(GCHandle) è valido solo mentre GCHandle è intatto. Non è necessario chiamare GCHandle.Free e non si deve lasciare che venga raccolto il numero GCHandle. Nel tuo codice, l'indirizzo è già privo di significato dal momento in cui lo memorizzi.

Ma dovresti semplicemente consentire a .NET di occuparsi della gestione del puntatore durante la garbage collection, utilizzando una variabile di tipo di riferimento. Quindi non è necessario saltare attraverso i cerchi. L'unica ragione per prendere l'indirizzo di un oggetto gestito è quando lo si passa a una funzione DLL nativa esistente che salverà il puntatore dopo che è ritornato. Ad esempio, è necessario con gli array di buffer OpenGL. NON è necessario, mai, quando si chiamano altri metodi C#.

Se SOMESTRUCT è in realtà un tipo di dati nativi utilizzato da una funzione DLL non menzionata, è necessario assicurarsi di mantenere lo GCHandle attivo. Solo finché esiste lo GCHandle il puntatore che hai ottenuto rimane valido.

+0

concordato. La risposta accettata non è corretta; tuttavia penso che ci sia di più nella storia che non conosciamo, altrimenti, perché tutto il lavoro extra quando il runtime gestirà correttamente il marshalling? – codekaizen

+0

@codekaizen: Sì, il requisito che "il tipo SOMESTRUCT non può essere modificato" deve avere alcune motivazioni che è necessario conoscere per poter risolvere correttamente il programma. –

+0

Il tipo SOMESTRUCT è una struttura di messaggio finestra con un "puntatore personalizzato". Questo puntatore era originariamente utilizzato (nel programma) per fare riferimento a stringhe contenenti oggetti serializzati, che funzionavano (tipo di) bene. Nel mio codice, alcune classi non erano serializzabili quindi dovevo trovare un'altra soluzione. In effetti, la soluzione accettata sembrava OK ma non fu mai testata, poiché sollevò più problemi che risolse; quindi ho rinunciato alla "puntatore/serializzazione" e ho usato un altro modo C# -ish di fare le cose. – slaphappy

2

Vuoi dire che si desidera lanciare il puntatore restituito di nuovo ad uno struct?

Simile a:

lvHitTestInfo = (LVHITTESTINFO)Marshal.PtrToStructure(lP, typeof(LVHITTESTINFO)); 

Dove lvHitTestInfo è una struttura e LP un puntatore.

Oppure non ho capito bene la tua domanda. Forse puoi spiegare di più (esempio di codice più completo).

+0

Sì e no. Voglio lanciare il puntatore restituito su un oggetto. Aggiungerò ulteriori dettagli alla mia domanda. – slaphappy

+0

Non ho notato che questo metodo funziona anche con gli oggetti. Questo è quello che stavo cercando. Grazie per l'aiuto ! – slaphappy

+0

Non ci sono mai andato ma per sapere se è possibile è necessario fornire una descrizione esatta di ciò che viene effettivamente restituito. A cosa punta esattamente il puntatore. Vedere, se si sta interagendo con codice non gestito, è molto improbabile che si possa eseguire il cast su un oggetto gestito. Non c'è modo di sapere cosa va dove. – Jeroen