Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Porblème P/INvoke et Callbacks

2 réponses
Avatar
Fabien Penso
Bonjour à tous.

J'ai une application en C# qui utilise une dll codée en C à l'aide de
DllImport. Ca marche presque mais j'ai des bugs aléatoires (une erreur
quand le code non managé appelle la callback codée en C#) de temps en temps.

Je soupconne les callbacks d'être garbage collectées même si je fais
tout pour qu'elles ne le soient pas.

Les callbacks sont toutes passées d'un seul coup à l'aide d'une
structure appelée phCallbacks. Je récupère le pointeur du delegate que
je créé pour le mettre dans la structure, que je passe plus tard à ma
fonction C/non managée.

Quelqu'un aurait une idée ? J'ai manqué un truc ?

Merci.

NB: le code est sur http://rafb.net/paste/results/ec4TIb23.html

2 réponses

Avatar
Mehdi
On Thu, 19 May 2005 13:25:32 +0200, Fabien Penso wrote:

J'ai une application en C# qui utilise une dll codée en C à l'aide de
DllImport. Ca marche presque mais j'ai des bugs aléatoires (une erreur
quand le code non managé appelle la callback codée en C#) de temps en temps.

Je soupconne les callbacks d'être garbage collectées même si je fais
tout pour qu'elles ne le soient pas.



Quelqu'un aurait une idée ? J'ai manqué un truc ?



Pas trop d'idées mais a tu essayé d'appeler GC.KeepAlive pour chacun de tes
delegate avant de les passer au code non manager afin de t'assurer qu''ils
ne sont pas garbage collectés trop tot ?
Avatar
Fabien Penso
Mehdi wrote:

Pas trop d'idées mais a tu essayé d'appeler GC.KeepAlive pour chacun de tes
delegate avant de les passer au code non manager afin de t'assurer qu''ils
ne sont pas garbage collectés trop tot ?



Bon en fait j'ai la réponse, il faut que je garde les delegates et là je
ne gardais que les pointeurs vers les delegates (a coup d'astuce à la con).

Donc le truc à se rappeler, c'est de s'assurer que les callbacks ne sont
pas garbages collectées, sinon ça foire à un moment ou un autre. Dans le
cas ou on passe une structure de callbacks les callbacks ne sont pas
marshallés, il faut donc récupérer les pointeurs (voir le hack à la con
dans le code) de chaque callback, les mettre dans la structure, et
passer celle là à la fonction native; tout en gardant les delegates dans
une autre structure.

Voir le code attaché (merci à Jonathan Pryor de Mono).

public class SIPphapi {

private phCallbacks callbacksfunc;

// We define type of callbacks
public delegate void CallBackInt(int x, int y);
public delegate void CallBackPtr(int x, IntPtr info);
public delegate void CallBackStrings(String a, String b, String c);

# region struct de callback
[StructLayout(LayoutKind.Sequential)]
public struct phCallbacks {
public IntPtr callProgress;
public IntPtr transferProgress;
public IntPtr confProgress;
public IntPtr regProgress;
public IntPtr msgProgress;
public IntPtr onNotify;
public phCallbacks(IntPtr c1, IntPtr t, IntPtr c2, IntPtr
r, IntPtr m, IntPtr o) {
callProgress = c1;
confProgress = c2;
msgProgress = m;
onNotify = o;
regProgress = r;
transferProgress = t;
}
}
// Holds the delegate for not being garbage collected
private struct callBacksHolder {
public CallBackPtr callProgress;
public CallBackPtr transferProgress;
public CallBackPtr confProgress;
public CallBackInt regProgress;
public CallBackPtr msgProgress;
public CallBackStrings onNotify;
public callBacksHolder(CallBackPtr c1, CallBackPtr t,
CallBackPtr c2,
CallBackInt r, CallBackPtr m, CallBackStrings o) {
callProgress = c1;
confProgress = c2;
msgProgress = m;
onNotify = o;
regProgress = r;
transferProgress = t;
}

}
#endregion

// use a msvcrt function to return a pointer from the delegate
[DllImport("msvcrt")]
public static extern IntPtr strncpy(Delegate pd, IntPtr src,
int size);
static IntPtr GetFunctionPtrFromDelegate(Delegate d) {
// strncpy returns the buffer address (the marshaled
delegate pointer).
// We obviously don't copy anything
return strncpy(d, IntPtr.Zero, 0);
}

private callBacksHolder callbackdelegates;
public SIPphapi(ISIPCallBacks callbacks) {
this.callbackdelegates = new callBacksHolder(
new CallBackPtr(callProgress),
new CallBackPtr(transferProgress),
new CallBackPtr(confProgress),
new CallBackInt(regProgress),
new CallBackPtr(msgProgress),
new CallBackStrings(onNotify)
);

this.callbacksfunc = new phCallbacks(

GetFunctionPtrFromDelegate(this.callbackdelegates.callProgress),

GetFunctionPtrFromDelegate(this.callbackdelegates.transferProgress),

GetFunctionPtrFromDelegate(this.callbackdelegates.confProgress),

GetFunctionPtrFromDelegate(this.callbackdelegates.regProgress),

GetFunctionPtrFromDelegate(this.callbackdelegates.msgProgress),
GetFunctionPtrFromDelegate(this.callbackdelegates.onNotify)
);

this.callbacks = callbacks;

MAFONCTIONC(ref this.callbacks);
}

}